package com.twotoasters.jazzylistview;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AbsListView;
import com.nineoldandroids.view.ViewPropertyAnimator;
import com.twotoasters.jazzylistview.effects.CardsEffect;
import com.twotoasters.jazzylistview.effects.CurlEffect;
import com.twotoasters.jazzylistview.effects.FadeEffect;
import com.twotoasters.jazzylistview.effects.FanEffect;
import com.twotoasters.jazzylistview.effects.FlipEffect;
import com.twotoasters.jazzylistview.effects.FlyEffect;
import com.twotoasters.jazzylistview.effects.GrowEffect;
import com.twotoasters.jazzylistview.effects.HelixEffect;
import com.twotoasters.jazzylistview.effects.ReverseFlyEffect;
import com.twotoasters.jazzylistview.effects.SlideInEffect;
import com.twotoasters.jazzylistview.effects.StandardEffect;
import com.twotoasters.jazzylistview.effects.TiltEffect;
import com.twotoasters.jazzylistview.effects.TwirlEffect;
import com.twotoasters.jazzylistview.effects.WaveEffect;
import com.twotoasters.jazzylistview.effects.ZipperEffect;
import java.util.HashSet;
public class JazzyHelper implements AbsListView.OnScrollListener {
public static final int STANDARD = 0;
public static final int GROW = 1;
public static final int CARDS = 2;
public static final int CURL = 3;
public static final int WAVE = 4;
public static final int FLIP = 5;
public static final int FLY = 6;
public static final int REVERSE_FLY = 7;
public static final int HELIX = 8;
public static final int FAN = 9;
public static final int TILT = 10;
public static final int ZIPPER = 11;
public static final int FADE = 12;
public static final int TWIRL = 13;
public static final int SLIDE_IN = 14;
public static final int OPAQUE = 255, TRANSPARENT = 0;
private JazzyEffect mTransitionEffect = null;
private boolean mIsScrolling = false;
private int mFirstVisibleItem = -1;
private int mLastVisibleItem = -1;
private int mDuration = 600;
private AbsListView.OnScrollListener mAdditionalOnScrollListener;
private boolean mOnlyAnimateNewItems;
private final HashSet<Integer> mAlreadyAnimatedItems;
public JazzyHelper(Context context, AttributeSet attrs) {
mAlreadyAnimatedItems = new HashSet<Integer>();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.JazzyListView);
int transitionEffect = a.getInteger(R.styleable.JazzyListView_effect, STANDARD);
mOnlyAnimateNewItems = a.getBoolean(R.styleable.JazzyListView_only_animate_new_items, false);
a.recycle();
setTransitionEffect(transitionEffect);
}
public void setOnScrollListener(AbsListView.OnScrollListener l) {
// hijack the scroll listener setter and have this list also notify the additional listener
mAdditionalOnScrollListener = l;
}
/**
* @see AbsListView.OnScrollListener#onScroll
*/
@Override
public final void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
boolean shouldAnimateItems = (mFirstVisibleItem != -1 && mLastVisibleItem != -1);
int lastVisibleItem = firstVisibleItem + visibleItemCount - 1;
if (mIsScrolling && shouldAnimateItems) {
int indexAfterFirst = 0;
while (firstVisibleItem + indexAfterFirst < mFirstVisibleItem) {
View item = view.getChildAt(indexAfterFirst);
doJazziness(item, firstVisibleItem + indexAfterFirst, -1);
indexAfterFirst++;
}
int indexBeforeLast = 0;
while (lastVisibleItem - indexBeforeLast > mLastVisibleItem) {
View item = view.getChildAt(lastVisibleItem - firstVisibleItem - indexBeforeLast);
doJazziness(item, lastVisibleItem - indexBeforeLast, 1);
indexBeforeLast++;
}
} else if (!shouldAnimateItems) {
for (int i = firstVisibleItem; i < visibleItemCount; i++) {
mAlreadyAnimatedItems.add(i);
}
}
mFirstVisibleItem = firstVisibleItem;
mLastVisibleItem = lastVisibleItem;
notifyAdditionalScrollListener(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
/**
* Initializes the item view and triggers the animation.
*
* @param item The view to be animated.
* @param position The index of the view in the list.
* @param scrollDirection Positive number indicating scrolling down, or negative number indicating scrolling up.
*/
private void doJazziness(View item, int position, int scrollDirection) {
if (mIsScrolling) {
if (mOnlyAnimateNewItems && mAlreadyAnimatedItems.contains(position)) {
return;
}
ViewPropertyAnimator animator = com.nineoldandroids.view.ViewPropertyAnimator
.animate(item)
.setDuration(mDuration)
.setInterpolator(new AccelerateDecelerateInterpolator());
scrollDirection = scrollDirection > 0 ? 1 : -1;
mTransitionEffect.initView(item, position, scrollDirection);
mTransitionEffect.setupAnimation(item, position, scrollDirection, animator);
animator.start();
mAlreadyAnimatedItems.add(position);
}
}
/**
* @see AbsListView.OnScrollListener#onScrollStateChanged
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch(scrollState) {
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
mIsScrolling = false;
break;
case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
mIsScrolling = true;
break;
default: break;
}
}
public void setTransitionEffect(int transitionEffect) {
switch (transitionEffect) {
case STANDARD: setTransitionEffect(new StandardEffect()); break;
case GROW: setTransitionEffect(new GrowEffect()); break;
case CARDS: setTransitionEffect(new CardsEffect()); break;
case CURL: setTransitionEffect(new CurlEffect()); break;
case WAVE: setTransitionEffect(new WaveEffect()); break;
case FLIP: setTransitionEffect(new FlipEffect()); break;
case FLY: setTransitionEffect(new FlyEffect()); break;
case REVERSE_FLY: setTransitionEffect(new ReverseFlyEffect()); break;
case HELIX: setTransitionEffect(new HelixEffect()); break;
case FAN: setTransitionEffect(new FanEffect()); break;
case TILT: setTransitionEffect(new TiltEffect()); break;
case ZIPPER: setTransitionEffect(new ZipperEffect()); break;
case FADE: setTransitionEffect(new FadeEffect()); break;
case TWIRL: setTransitionEffect(new TwirlEffect()); break;
case SLIDE_IN: setTransitionEffect(new SlideInEffect()); break;
default: break;
}
}
public void setDuration(int transitionDurationMillis) {
mDuration = transitionDurationMillis;
}
public void setTransitionEffect(JazzyEffect transitionEffect) {
mTransitionEffect = transitionEffect;
}
public void setShouldOnlyAnimateNewItems(boolean onlyAnimateNew) {
mOnlyAnimateNewItems = onlyAnimateNew;
}
/**
* Notifies the OnScrollListener of an onScroll event, since JazzyListView is the primary listener for onScroll events.
*/
private void notifyAdditionalScrollListener(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mAdditionalOnScrollListener != null) {
mAdditionalOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
}
}