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
- rewrite
DefaultItemAnimator
therecordPreLayoutInformation()
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