
com.nhaarman.listviewanimations.swinginadapters.AnimationAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of library Show documentation
Show all versions of library Show documentation
ListViewAnimations library
The newest version!
/*
* Copyright 2013 Niek Haarman
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nhaarman.listviewanimations.swinginadapters;
import android.annotation.SuppressLint;
import android.os.Build;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import com.nhaarman.listviewanimations.BaseAdapterDecorator;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;
/**
* A {@link BaseAdapterDecorator} class which applies multiple {@link Animator}s at once to
* views when they are first shown. The Animators applied include the animations
* specified in {@link #getAnimators(ViewGroup, View)}, plus an alpha transition.
*/
public abstract class AnimationAdapter extends BaseAdapterDecorator {
protected static final long DEFAULTANIMATIONDELAYMILLIS = 100;
protected static final long DEFAULTANIMATIONDURATIONMILLIS = 300;
private static final long INITIALDELAYMILLIS = 150;
private static final String ALPHA = "alpha";
private final SparseArray mAnimators;
private long mAnimationStartMillis;
private int mFirstAnimatedPosition;
private int mLastAnimatedPosition;
private boolean mHasParentAnimationAdapter;
private boolean mShouldAnimate = true;
private long mInitialDelayMillis = INITIALDELAYMILLIS;
private long mAnimationDelayMillis = DEFAULTANIMATIONDELAYMILLIS;
private long mAnimationDurationMillis = DEFAULTANIMATIONDURATIONMILLIS;
public AnimationAdapter(final BaseAdapter baseAdapter) {
super(baseAdapter);
mAnimators = new SparseArray();
mAnimationStartMillis = -1;
mFirstAnimatedPosition = -1;
mLastAnimatedPosition = -1;
if (baseAdapter instanceof AnimationAdapter) {
((AnimationAdapter) baseAdapter).setHasParentAnimationAdapter(true);
}
}
/**
* Call this method to reset animation status on all views. The next time
* {@link #notifyDataSetChanged()} is called on the base adapter, all views will
* animate again. Will also call {@link #setShouldAnimate(boolean)} with a value of true.
*/
public void reset() {
mAnimators.clear();
mFirstAnimatedPosition = -1;
mLastAnimatedPosition = -1;
mAnimationStartMillis = -1;
mShouldAnimate = true;
if (getDecoratedBaseAdapter() instanceof AnimationAdapter) {
((AnimationAdapter) getDecoratedBaseAdapter()).reset();
}
}
/**
* Set whether to animate the {@link View}s or not.
* @param shouldAnimate true if the Views should be animated.
*/
public void setShouldAnimate(final boolean shouldAnimate) {
mShouldAnimate = shouldAnimate;
}
/**
* Set the starting position for which items should animate. Given position will animate as well.
* Will also call setShouldAnimate(true).
* @param position the position.
*/
@SuppressWarnings("UnusedDeclaration")
public void setShouldAnimateFromPosition(final int position) {
mShouldAnimate = true;
mFirstAnimatedPosition = position - 1;
mLastAnimatedPosition = position - 1;
}
/**
* Set the starting position for which items should animate as the first position which isn't currently visible on screen.
* This call is also valid when the {@link View}s haven't been drawn yet.
* Will also call setShouldAnimate(true).
*/
@SuppressWarnings("UnusedDeclaration")
public void setShouldAnimateNotVisible() {
if (getAbsListView() == null) {
throw new IllegalStateException("Call setListView() on this AnimationAdapter before setShouldAnimateNotVisible()!");
}
mShouldAnimate = true;
mFirstAnimatedPosition = getAbsListView().getLastVisiblePosition();
mLastAnimatedPosition = getAbsListView().getLastVisiblePosition();
}
@Override
public final View getView(final int position, final View convertView, final ViewGroup parent) {
if (!mHasParentAnimationAdapter) {
if (getAbsListView() == null) {
throw new IllegalStateException("Call setListView() on this AnimationAdapter before setAdapter()!");
}
if (convertView != null) {
cancelExistingAnimation(convertView);
}
}
View itemView = super.getView(position, convertView, parent);
if (!mHasParentAnimationAdapter) {
animateViewIfNecessary(position, itemView, parent);
}
return itemView;
}
private void cancelExistingAnimation(final View convertView) {
int hashCode = convertView.hashCode();
Animator animator = mAnimators.get(hashCode);
if (animator != null) {
animator.end();
mAnimators.remove(hashCode);
}
}
private void animateViewIfNecessary(final int position, final View view, final ViewGroup parent) {
boolean isMeasuringGridViewItem = getAbsListView() instanceof GridView && parent.getHeight() == 0;
if (position > mLastAnimatedPosition && mShouldAnimate && !isMeasuringGridViewItem) {
if (mFirstAnimatedPosition == -1) {
mFirstAnimatedPosition = position;
}
animateView(parent, view);
mLastAnimatedPosition = position;
}
}
private void animateView(final ViewGroup parent, final View view) {
if (mAnimationStartMillis == -1) {
mAnimationStartMillis = System.currentTimeMillis();
}
ViewHelper.setAlpha(view, 0);
Animator[] childAnimators;
if (mDecoratedBaseAdapter instanceof AnimationAdapter) {
childAnimators = ((AnimationAdapter) mDecoratedBaseAdapter).getAnimators(parent, view);
} else {
childAnimators = new Animator[0];
}
Animator[] animators = getAnimators(parent, view);
Animator alphaAnimator = ObjectAnimator.ofFloat(view, ALPHA, 0, 1);
AnimatorSet set = new AnimatorSet();
set.playTogether(concatAnimators(childAnimators, animators, alphaAnimator));
set.setStartDelay(calculateAnimationDelay());
set.setDuration(getAnimationDurationMillis());
set.start();
mAnimators.put(view.hashCode(), set);
}
private Animator[] concatAnimators(final Animator[] childAnimators, final Animator[] animators, final Animator alphaAnimator) {
Animator[] allAnimators = new Animator[childAnimators.length + animators.length + 1];
int i;
for (i = 0; i < animators.length; ++i) {
allAnimators[i] = animators[i];
}
for (Animator childAnimator : childAnimators) {
allAnimators[i] = childAnimator;
++i;
}
allAnimators[allAnimators.length - 1] = alphaAnimator;
return allAnimators;
}
@SuppressLint("NewApi")
private long calculateAnimationDelay() {
long delay;
int lastVisiblePosition = getAbsListView().getLastVisiblePosition();
int firstVisiblePosition = getAbsListView().getFirstVisiblePosition();
int numberOfItemsOnScreen = lastVisiblePosition - firstVisiblePosition;
int numberOfAnimatedItems = mLastAnimatedPosition - mFirstAnimatedPosition;
if (numberOfItemsOnScreen + 1 < numberOfAnimatedItems) {
delay = getAnimationDelayMillis();
if (getAbsListView() instanceof GridView && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
delay += getAnimationDelayMillis() * ((mLastAnimatedPosition + 1) % ((GridView) getAbsListView()).getNumColumns());
}
} else {
long delaySinceStart = (mLastAnimatedPosition - mFirstAnimatedPosition + 1) * getAnimationDelayMillis();
delay = mAnimationStartMillis + getInitialDelayMillis() + delaySinceStart - System.currentTimeMillis();
}
return Math.max(0, delay);
}
/**
* Set whether this AnimationAdapter is encapsulated by another
* AnimationAdapter. When this is set to true, this AnimationAdapter does
* not apply any animations to the views. Should not be set explicitly, the
* AnimationAdapter class manages this by itself.
*/
public void setHasParentAnimationAdapter(final boolean hasParentAnimationAdapter) {
mHasParentAnimationAdapter = hasParentAnimationAdapter;
}
/**
* Get the delay in milliseconds before the first animation should start. Defaults to {@value #INITIALDELAYMILLIS}.
*/
protected long getInitialDelayMillis() {
return mInitialDelayMillis;
}
/**
* Set the delay in milliseconds before the first animation should start. Defaults to {@value #INITIALDELAYMILLIS}.
* @param delayMillis the time in milliseconds.
*/
public void setInitialDelayMillis(final long delayMillis) {
mInitialDelayMillis = delayMillis;
}
/**
* Get the delay in milliseconds before an animation of a view should start. Defaults to {@value #DEFAULTANIMATIONDELAYMILLIS}.
*/
protected long getAnimationDelayMillis() {
return mAnimationDelayMillis;
}
/**
* Set the delay in milliseconds before an animation of a view should start. Defaults to {@value #DEFAULTANIMATIONDELAYMILLIS}.
* @param delayMillis the time in milliseconds.
*/
@SuppressWarnings("UnusedDeclaration")
public void setAnimationDelayMillis(final long delayMillis) {
mAnimationDelayMillis = delayMillis;
}
/**
* Get the duration of the animation in milliseconds. Defaults to {@value #DEFAULTANIMATIONDURATIONMILLIS}.
*/
protected long getAnimationDurationMillis() {
return mAnimationDurationMillis;
}
/**
* Set the duration of the animation in milliseconds. Defaults to {@value #DEFAULTANIMATIONDURATIONMILLIS}.
* @param durationMillis the time in milliseconds.
*/
@SuppressWarnings("UnusedDeclaration")
public void setAnimationDurationMillis(final long durationMillis) {
mAnimationDurationMillis = durationMillis;
}
/**
* Get the Animators to apply to the views. In addition to the returned
* Animators, an alpha transition will be applied to the view.
*
* @param parent
* The parent of the view
* @param view
* The view that will be animated, as retrieved by getView()
*/
public abstract Animator[] getAnimators(ViewGroup parent, View view);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy