This is the second article about RecyclerView, which talks about how to customize Item animations, but please note that this article does not include specific implementation methods of animations, but only tells you how to customize animations and how to refer to the source code.
We know that RecyclerView will use DefaultItemAnimator by default, so if we need to customize animations, we should read the source code of this class well, so that we not only learn how to customize, but also learn Android's design patterns.
Let’s figure out one thing first. DefaultItemAnimator inherits from SimpleItemAnimator, and SimpleItemAnimator inherits from, so if you need to customize animations, the easiest way is to inherit SimpleItemAnimator. Secondly, there are four types of animations, namely Add, Remove, Move and Change. Here we will only list Remove and learn from one example.
Let’s first look at the source code in SimpleItemAnimator. There are several important methods in SimpleItemAnimator:
@Override public boolean animateDisappearance(@NonNull ViewHolder viewHolder, @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) { int oldLeft = ; int oldTop = ; View disappearingItemView = ; int newLeft = postLayoutInfo == null ? () : ; int newTop = postLayoutInfo == null ? () : ; if (!() && (oldLeft != newLeft || oldTop != newTop)) { (newLeft, newTop, newLeft + (), newTop + ()); if (DEBUG) { (TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView); } return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop); } else { if (DEBUG) { (TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView); } return animateRemove(viewHolder); } }
Analysis:This function is rewritten. The parameters in the interface are ViewHolder, prelayoutInfo and postLayoutInfo. The first parameter refers to the ViewHolder of Item. The View can be obtained through the itemView of this object. The second parameter refers to the location information before Item is deleted, and the third refers to the new location information. Next, we will determine whether the ViewHolder has been removed and whether the position has changed. Then we call the abstract method of animateRemove. If we want to customize the animation, we need to implement it (callback idea).
public final void dispatchRemoveStarting(ViewHolder item) { onRemoveStarting(item); } public void onRemoveStarting(ViewHolder item) { }
Analysis:dispatchRemoveStaring is a final method, which cannot be rewritten. If we need to process some logic at the beginning of Remove, we need to call this method in the animateRemove method. This method will execute an onRemoveStaring method, which allows us to rewrite, so the logic should be written in onRemoveStaring. When we call dispatchRemoveStaring, onRemoveStaring will be executed.
I only talked about two here, but there are more than two other actions. . .
Therefore, when we inherit SimpleItemAnimator, we need to implement some methods, generally as follows:
① animateRemove (Add, Move and Change): These methods will call back when the animation occurs. Generally, the animation and properties of each Item will be recorded in this method using a list.
② endAnimation and endAnimations: Callbacks are when one Item or multiple Items need to be stopped immediately.
③ isRunning: If you need to slide smoothly, you must rewrite this method. Many times, for example, sliding and stuttering when the network is loading, this method is logically wrong.
④ run'PendingAnimations: This is the most important method. Because methods such as animateDisappearence return values returned by methods such as animateRemove, and this method is based on these values to determine whether there is a prepared animation to play. If so, this method will be called back. In this method we need to process the animation of each action (Remove, Add, Move and Change)
So, our general steps are:
① Create a subclass of SimpleItemAnimator
②Create an action list for each action
③Rewrite methods such as animateRemove. When an action occurs in the interface, these functions will be called back. Record here and return true so that run'PendingAnimations starts execution
④Rewrite run'PendingAnimations. When the method of ③ returns true, it is believed that the animation needs to be executed. We need to write the logic of animation execution here.
⑤Rewrite isRunning to provide the animation playback status, generally return whether the action list is empty
⑥ If necessary, rewrite endAnimation, endAnimations, onRemoveFinish and other methods
There are specific steps, but we are not clear about how to build it, so don’t worry. For the sake of convenience, Google has actually provided DefaultItemAnimator. We can refer to some of its source code. No one said that it makes sense than the source code. What we need is to have enough patience!
DefaultItemAnimator defines some ArrayList to store the information of the action, as follows:
private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>(); private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>(); @Override public boolean animateRemove(final ViewHolder holder) { resetAnimation(holder); (holder); return true; }
Analysis:You can see that the animatorRemove method directly adds the viewholder to the list and returns true
@Override public void runPendingAnimations() { boolean removalsPending = !(); boolean movesPending = !(); boolean changesPending = !(); boolean additionsPending = !(); if (!removalsPending && !movesPending && !additionsPending && !changesPending) { // nothing to animate return; } // First, remove stuff for (ViewHolder holder : mPendingRemovals) { animateRemoveImpl(holder); } (); // Next, move stuff ...... // Next, change stuff, to run in parallel with move animations ...... // Next, add stuff ...... }
Analysis:According to the above, runPendingAnimations will be executed. You can see that in this method, the action list is traversed and each Item executes the animatorRemoveImpl method. The other action methods are temporarily omitted. Those who are interested can read it themselves.
private void animateRemoveImpl(final ViewHolder holder) { final View view = ; final ViewPropertyAnimatorCompat animation = (view); (holder); (getRemoveDuration()) .alpha(0).setListener(new VpaListenerAdapter() { @Override public void onAnimationStart(View view) { dispatchRemoveStarting(holder); } @Override public void onAnimationEnd(View view) { (null); (view, 1); dispatchRemoveFinished(holder); (holder); dispatchFinishedWhenDone(); } }).start(); }
Analysis:You can see that the animatorRemoveImpl method implements the specific logic of the entire animation. The specific logic is not within the scope of this article. After we execute the animation, dispatchRemoveFinish is called in onAnimatorEnd in the animation Listener. Do you still remember this method? It will execute the onRemoveFinish method. The onRemoveFinish method can be rewritten for us. Then remove the item from the action list.
@Override public boolean isRunning() { return (!() || !() || !() || !() || !() || !() || !() || !() || !() || !() || !()); }
Analysis:The isRunning method actually returns the result based on whether the action list is empty.
There are other functions that you can read the source code by yourself.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.