An ItemAnimator is used

Trigger delete animation

mDatas.remove(position);
notifyItemRemoved(position)
Copy the code

Trigger add animation

mDatas.add(position,data);
notifyItemInserted(position)
Copy the code

Trigger change animation

mDatas.set(position,newData);
notifyItemChanged(position)
Copy the code

Using simple animations

//RecyclerView.LayoutManager.java
public boolean supportsPredictiveItemAnimations() {
    return false;
}
Copy the code

Add/remove/change are all fade in/out animations:

Using predictive animation

//RecyclerView.LayoutManager.java
public boolean supportsPredictiveItemAnimations() {
    return true;
}
Copy the code

Use with LayoutAnimation

RecyclerView supports LayoutAnimation just like regular viewgroups. Easy to use, set RecyclerView’s animateLayoutChanges and layoutAnimation properties.

case



Photo credit:Layout animations on RecyclerView



Photo credit:RecyclerView and LayoutAnimation implementation into animation (a) : List

Custom RecyclerView list animation

Case study: Custom change animation

Effect:

Code implementation:

1. Create a MyChangeAnimator class that inherits DefaultItemAnimator

private class MyChangeAnimator extends DefaultItemAnimator {
}
Copy the code

2. Rewrite DefaultItemAnimator canReuseUpdatedViewHolder () method.

@ Override public Boolean canReuseUpdatedViewHolder (RecyclerView ViewHolder ViewHolder) {/ / change the animation on the same ItemHolder execution return true; }Copy the code

3. Create a ColorTextInfo class that inherits ItemHolderInfo and adds two fields to record the color and text of item.

private class ColorTextInfo extends ItemHolderInfo {
    int color;
    String text;
}
Copy the code

4. Override DefaultItemAnimator obtainHolderInfo() and create a new ColorTextInfo object to return.

@Override
public ItemHolderInfo obtainHolderInfo() {
    return new ColorTextInfo();
}
Copy the code
  1. rewriteDefaultItemAnimatortherecordPreLayoutInformation()andrecordPostLayoutInformation()Method. Record color and text information before and after item changes.
public ItemHolderInfo recordPreLayoutInformation(RecyclerView.State state, RecyclerView.ViewHolder viewHolder, int changeFlags, List<Object> payloads) { ColorTextInfo info = (ColorTextInfo) super.recordPreLayoutInformation(state, viewHolder,changeFlags, payloads); Return getItemHolderInfo((MyViewHolder) viewHolder, info); } public ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state, @NonNull RecyclerView.ViewHolder viewHolder) { ColorTextInfo info = (ColorTextInfo) super.recordPostLayoutInformation(state, viewHolder); Return getItemHolderInfo((MyViewHolder) viewHolder, info); } private ItemHolderInfo getItemHolderInfo(MyViewHolder viewHolder, ColorTextInfo info) { final MyViewHolder myHolder = viewHolder; final int bgColor = ((ColorDrawable) myHolder.container.getBackground()).getColor(); info.color = bgColor; info.text = (String) myHolder.textView.getText(); return info; }Copy the code

6. Override the animateChange() method of DefaultItemAnimator to perform a custom change animation

Began to change the animation graph TD - > alphaold began to change the animation - > rotateold alphaold ([old color to black gradient]) - > | sequential | alphanew ([black to a new color gradient]) Rotateold ([old text x axis rotate 0 - > 90 degrees]) - > | sequential | rotatenew ([new text x axis rotate - 90 - > 0 degrees]) alphanew - > change end animation rotatenew - > change the end of the animation
public boolean animateChange(@NonNull final RecyclerView.ViewHolder oldHolder, @NonNull final RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) { ... final MyViewHolder viewHolder = (MyViewHolder) newHolder; ColorTextInfo oldInfo = (ColorTextInfo) preInfo; ColorTextInfo newInfo = (ColorTextInfo) postInfo; int oldColor = oldInfo.color; int newColor = newInfo.color; final String oldText = oldInfo.text; final String newText = newInfo.text; LinearLayout newContainer = viewHolder.container; final TextView newTextView = viewHolder.textView; ObjectAnimator fadeToBlack = null, fadeFromBlack; fadeToBlack = ObjectAnimator.ofInt(newContainer, "backgroundColor", startColor, Color.BLACK); fadeToBlack.setEvaluator(mColorEvaluator); FadeFromBlack = objectAnimator. ofInt(newContainer, "backgroundColor", color.black, newColor) BgAnim = new AnimatorSet(); bgAnim.playSequentially(fadeToBlack, fadeFromBlack); ObjectAnimator oldTextRotate = null, newTextRotate; oldTextRotate = ObjectAnimator.ofFloat(newTextView, View.ROTATION_X, 0, 90); oldTextRotate.setInterpolator(mAccelerateInterpolator); oldTextRotate.addListener(new AnimatorListenerAdapter() { boolean mCanceled = false; @override public void onAnimationStart(Animator animation) {newTextView.settext (oldText); } @Override public void onAnimationCancel(Animator animation) { mCanceled = true; } @Override public void onAnimationEnd(Animator animation) { if (! MCanceled) {// newText newtextview.settext (newText) is displayed when the animation ends; }}}); NewTextRotate = objectAnimator.offloat (newTextView, view.rotation_x, -90, 0); newTextRotate.setInterpolator(mDecelerateInterpolator); TextAnim = new AnimatorSet(); textAnim.playSequentially(oldTextRotate, newTextRotate); ChangeAnim = new AnimatorSet(); changeAnim.playTogether(bgAnim, textAnim); changeAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { dispatchAnimationFinished(newHolder); . }}); changeAnim.start(); return true; }Copy the code

7. Set RecyclerView’s ItemAnimator to a custom MyChangeAnimator

mRecyclerView.setItemAnimator(mChangeAnimator);
Copy the code

This is the simplified code. The official full demo also includes boundary case handling, which deals with the situation that a new change animation is triggered when the last change animation is not finished executing. Code address :github.com/android/vie…

Customize add and DEL animations

Target effect:

Code implementation:

1. Copy DefaultItemAnimator source, named DefaultItemAnimatorOpen. Java

2. Overwrite the animation implementation for adding and removing (this step requires changing the visibility of some methods and properties in DefaultItemAnimatorOpen to protected).

Refer to the implementation of the corresponding method in DefaultItemAnimatorOpen and modify the animator-related code:

class CustomAddDelAnimation : DefaultItemAnimatorOpen() { override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean {/ / rewrite item add animation resetAnimation (holder) / / will be the new item x axis rotate 90 degree holder. The itemView. RotationX = 90 f mPendingAdditions.add(holder) return true } override fun animateAddImpl(holder: Add (holder) holder.itemView.animate().apply {// Add an item to an object by rotating it 90->0 degrees around the X-axis. rotationX(0f) duration = addDuration interpolator = DecelerateInterpolator(3f) setListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator?) { dispatchAddStarting(holder) } override fun onAnimationCancel(animation: Animator?) { ViewHelper.clear(holder.itemView) } override fun onAnimationEnd(animation: Animator) { ViewHelper.clear(holder.itemView) dispatchAddFinished(holder) mAddAnimations.remove(holder) dispatchFinishedWhenDone() } }) }.start() } override fun animateRemove(holder: RecyclerView.ViewHolder): ResetAnimation (holder) mPendingRemovals. Add (holder) return true} Override fun animateRemoveImpl(holder: MRemoveAnimations. Add (holder) holder.itemView.animate().apply {// Remove an item and rotate it 0->90 degrees around the X-axis. rotationX(90f) duration = addDuration interpolator = DecelerateInterpolator(3f) setListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator?) { dispatchRemoveStarting(holder) } override fun onAnimationCancel(animation: Animator?) { ViewHelper.clear(holder.itemView) } override fun onAnimationEnd(animation: Animator) { ViewHelper.clear(holder.itemView) dispatchRemoveFinished(holder) mRemoveAnimations.remove(holder) dispatchFinishedWhenDone() } }) }.start() } }Copy the code

The demo address: HoopAndroidDemos

Four RecyclerView list animation principle brief analysis

classDiagram ItemAnimator <|.. ItemAnimatorListener: rely on ItemAnimator < |.. ItemAnimatorFinishedListener: rely on ItemAnimator < |.. ItemHolderInfo : Rely on ItemAnimator < | - SimpleItemAnimator: inheritance SimpleItemAnimator < | - DefaultItemAnimator: inheritance < < the abstract > > ItemAnimator class ItemAnimator <<interface>> ItemAnimatorListener class ItemAnimatorListener <<interface>> ItemAnimatorFinishedListener class ItemAnimatorFinishedListener class ItemHolderInfo <<abstract>> SimpleItemAnimator class SimpleItemAnimator

By default, the order in which animations are executed is predictable

Graph of TD start ([" execution delay item of the animation (the next frame) "]] -- > | | to perform delete animation remove/" default effect for fading out "remove - > | | mobile animation move/" default effect for translation" remove - > | change | animation change [" default effect to fade out + enter "] move - > add [add animation "(the default effect to enter)"] change - > add to add - > | end item animation execution | endanimation ([reset state])

Is the list animation executed immediately? When the animateXXX() method returns true, execution is deferred until the next frame rate. Execute immediately if false is returned. DefaultItemAnimator animations are executed on the next frame.

List animation implementation process

Custom change animation that executes immediately:

sequenceDiagram
RecyclerView->>ItenAnimator: dispatchLayoutStep1()
ItenAnimator->>RecyclerView: recordPreLayoutInformation()
RecyclerView-)ItenAnimator: dispatchLayoutStep3()
ItenAnimator->>ItenAnimator: recordPostLayoutInformation()
ItenAnimator->>ItenAnimator: animateChange()

Add animation delayed by default:

sequenceDiagram
RecyclerView->>RecyclerView: dispatchLayoutStep3()
RecyclerView-)ItenAnimator: animateMove()
RecyclerView-)ItenAnimator: animateAdd()
RecyclerView-->>ItenAnimator: postAnimationRunner()
ItenAnimator->>ItenAnimator: animateMoveImpl
ItenAnimator->>ItenAnimator: animateAddImpl

InstaMaterial – RecyclerView animations done right (thanks to Android Dev Summit!) recyclerview-animators