Skip to content

Instantly share code, notes, and snippets.

@kosiara
Last active June 12, 2018 12:12
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kosiara/b5fcf5910fbdd37b1222 to your computer and use it in GitHub Desktop.
Save kosiara/b5fcf5910fbdd37b1222 to your computer and use it in GitHub Desktop.
Android RecyclerView sequential items fade-in animation
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class MyAlphaInAnimationAdapter extends MyAnimationAdapter {
private static final float DEFAULT_ALPHA_FROM = 0.0F;
private final float mFrom;
private RecyclerView recyclerView;
public MyAlphaInAnimationAdapter(RecyclerView.Adapter adapter) {
this(adapter, 0.0F);
}
public MyAlphaInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
super(adapter);
this.mFrom = from;
}
protected Animator[] getAnimators(View view) {
view.setAlpha(0);
return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", new float[]{this.mFrom, 1.0F})};
}
protected RecyclerView getRecyclerView() {
return recyclerView;
}
public void setRecyclerView(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
}
import android.animation.Animator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
public abstract class MyAnimationAdapter extends Adapter<ViewHolder> {
private Adapter<ViewHolder> mAdapter;
private int mDuration = 300;
private Interpolator mInterpolator = new LinearInterpolator();
private int mLastPosition = -1;
private boolean isFirstOnly = true;
private int mCounter;
private boolean mAnimsInitialized;
public MyAnimationAdapter(Adapter<ViewHolder> adapter) {
this.mAdapter = adapter;
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return this.mAdapter.onCreateViewHolder(parent, viewType);
}
public void onBindViewHolder(ViewHolder holder, int position) {
this.mAdapter.onBindViewHolder(holder, position);
if(this.isFirstOnly && position <= this.mLastPosition) {
MyViewHelper.clear(holder.itemView);
} else {
Animator[] animators = this.getAnimators(holder.itemView);
int animArrLength = animators.length;
LinearLayoutManager layoutManager = ((LinearLayoutManager)this.getRecyclerView().getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
if (mAnimsInitialized == false && firstVisiblePosition == 0)
for (int i = 0; i < animArrLength; i++) {
final Animator anim = animators[i];
anim.setDuration((long) this.mDuration);
anim.setInterpolator(this.mInterpolator);
increaseCounter();
anim.setStartDelay(75 * position);
anim.addListener(new Animator.AnimatorListener() {
@Override public void onAnimationStart(Animator animation) {}
@Override
public void onAnimationEnd(Animator animation) {
if (decreaseCounter())
mAnimsInitialized = true;
}
@Override public void onAnimationCancel(Animator animation) {}
@Override public void onAnimationRepeat(Animator animation) {}
});
anim.start();
}
else
holder.itemView.setAlpha(1);
this.mLastPosition = position;
}
}
protected synchronized boolean decreaseCounter() {
mCounter--;
return mCounter == 0;
}
public synchronized int getCounter() {
return mCounter;
}
public synchronized void increaseCounter() {
mCounter++;
}
public int getItemCount() {
return this.mAdapter.getItemCount();
}
public void setDuration(int duration) {
this.mDuration = duration;
}
public void setInterpolator(Interpolator interpolator) {
this.mInterpolator = interpolator;
}
public void setStartPosition(int start) {
this.mLastPosition = start;
}
protected abstract Animator[] getAnimators(View var1);
protected abstract RecyclerView getRecyclerView();
public void setFirstOnly(boolean firstOnly) {
this.isFirstOnly = firstOnly;
}
public int getItemViewType(int position) {
return this.mAdapter.getItemViewType(position);
}
public Adapter<ViewHolder> getWrappedAdapter() {
return this.mAdapter;
}
}
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.animation.Interpolator;
public final class MyViewHelper {
public static void clear(View v) {
ViewCompat.setAlpha(v, 1.0F);
ViewCompat.setScaleY(v, 1.0F);
ViewCompat.setScaleX(v, 1.0F);
ViewCompat.setTranslationY(v, 0.0F);
ViewCompat.setTranslationX(v, 0.0F);
ViewCompat.setRotation(v, 0.0F);
ViewCompat.setRotationY(v, 0.0F);
ViewCompat.setRotationX(v, 0.0F);
v.setPivotY((float)(v.getMeasuredHeight() / 2));
ViewCompat.setPivotX(v, (float)(v.getMeasuredWidth() / 2));
ViewCompat.animate(v).setInterpolator((Interpolator)null);
}
}
RecyclerView myRecyclerView = getActivity().findViewById(R.id.my_favorite_recycler_view);
FavoriteItemsListAdapter myAdapter = new FavoriteItemsListAdapter();
MyAlphaInAnimationAdapter alphaInAnimationAdapter = new MyAlphaInAnimationAdapter(myAdapter);
alphaInAnimationAdapter.setRecyclerView(mFavoriteRecyclerView);
alphaInAnimationAdapter.setDuration(300);
myRecyclerView.setAdapter(alphaInAnimationAdapter);
@kosiara
Copy link
Author

kosiara commented Sep 4, 2015

This adapter aims to create a sequential RecyclerView items' animation.
Items appear in order, top to bottom. The animation works when the RecyclerView is first created and does NOT work when items are scrolled down.

Performance is good to average. I wouldn't recommend using alpha-in animation on older phones.

Live preview:
http://i.imgur.com/aVVeCZK.gif

Live preview

@kosiara
Copy link
Author

kosiara commented Sep 4, 2015

Image 1

Image 2

Image 3

Image 4

@usmanrana07
Copy link

Can you highlight the major difference than this one? i found a similar adapter at given link:
https://gist.github.com/jakubkinst/7840d707558751acae66

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment