package com.abewy.android.apps.klyph.adapter.animation; /* * Based on work of Niek Haarman * This animator remove alpha animations * * 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. */ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import com.haarman.listviewanimations.BaseAdapterDecorator; import com.haarman.listviewanimations.swinginadapters.AnimationAdapter; /** * A BaseAdapterDecorator class which applies multiple Animators at once to * views when they are first shown. The Animators applied include the animations * specified in getAnimators(ViewGroup, View), plus an alpha transition. */ public abstract class KlyphAnimationAdapter extends BaseAdapterDecorator { protected static final long DEFAULTANIMATIONDELAYMILLIS = 100; protected static final long DEFAULTANIMATIONDURATIONMILLIS = 300; private static final long INITIALDELAYMILLIS = 150; private SparseArray<AnimationInfo> mAnimators; private long mAnimationStartMillis; private int mLastAnimatedPosition; private boolean animationsEnabled = true; private int nextDeactivated = 0; private boolean mHasParentAnimationAdapter; public KlyphAnimationAdapter(BaseAdapter baseAdapter) { super(baseAdapter); mAnimators = new SparseArray<AnimationInfo>(); mAnimationStartMillis = -1; mLastAnimatedPosition = -1; if (baseAdapter instanceof AnimationAdapter) { ((AnimationAdapter) baseAdapter).setHasParentAnimationAdapter(true); } } public void activateAnimations() { animationsEnabled = true; } public void deactivateAnimations() { animationsEnabled = false; } public void deactivateNext(int count) { this.nextDeactivated = count; } /** * Call this method to reset animation status on all views. The next time * notifyDataSetChanged() is called on the base adapter, all views will * animate again. */ public void reset() { mAnimators.clear(); mLastAnimatedPosition = -1; mAnimationStartMillis = -1; if (getDecoratedBaseAdapter() instanceof AnimationAdapter) { ((AnimationAdapter) getDecoratedBaseAdapter()).reset(); } } @Override public final View getView(int position, View convertView, ViewGroup parent) { boolean alreadyStarted = false; if (!mHasParentAnimationAdapter) { if (getListView() == null) { throw new IllegalStateException("Call setListView() on this AnimationAdapter before setAdapter()!"); } if (convertView != null) { int hashCode = convertView.hashCode(); AnimationInfo animationInfo = mAnimators.get(hashCode); if (animationInfo != null) { if (animationInfo.position != position) { animationInfo.animator.end(); mAnimators.remove(hashCode); } else { alreadyStarted = true; } } } } View itemView = super.getView(position, convertView, parent); if (nextDeactivated <= 0) { if (!mHasParentAnimationAdapter && !alreadyStarted && animationsEnabled) { animateViewIfNecessary(position, itemView, parent); } } else { nextDeactivated--; } return itemView; } private void animateViewIfNecessary(int position, View view, ViewGroup parent) { if (position > mLastAnimatedPosition && !mHasParentAnimationAdapter) { animateView(position, parent, view); mLastAnimatedPosition = position; } } private void animateView(int position, ViewGroup parent, View view) { if (mAnimationStartMillis == -1) { mAnimationStartMillis = System.currentTimeMillis(); } hideView(view); 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(); showView(view); mAnimators.put(view.hashCode(), new AnimationInfo(position, set)); } private void showView(View view) { ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1); AnimatorSet set = new AnimatorSet(); set.play(animator); set.setStartDelay(calculateAnimationDelay()); set.setDuration(0); set.start(); } private void hideView(View view) { ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0); AnimatorSet set = new AnimatorSet(); set.play(animator); set.setDuration(0); set.start(); } private Animator[] concatAnimators(Animator[] childAnimators, Animator[] animators/* * , * 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 (int j = 0; j < childAnimators.length; ++j) { allAnimators[i] = childAnimators[j]; ++i; } // allAnimators[allAnimators.length - 1] = alphaAnimator; return allAnimators; } private long calculateAnimationDelay() { long delay; int numberOfItems = getListView().getLastVisiblePosition() - getListView().getFirstVisiblePosition(); if (numberOfItems + 1 < mLastAnimatedPosition) { delay = getAnimationDelayMillis(); } else { long delaySinceStart = (mLastAnimatedPosition + 1) * getAnimationDelayMillis(); delay = mAnimationStartMillis + INITIALDELAYMILLIS + 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(boolean hasParentAnimationAdapter) { mHasParentAnimationAdapter = hasParentAnimationAdapter; } /** * Get the delay in milliseconds before an animation of a view should start. */ protected abstract long getAnimationDelayMillis(); /** * Get the duration of the animation in milliseconds. */ protected abstract long getAnimationDurationMillis(); /** * 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); private class AnimationInfo { public int position; public Animator animator; public AnimationInfo(int position, Animator animator) { this.position = position; this.animator = animator; } } }