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;
}
}
}