Advanced usage of Recyclerview-custom animations

Source: Internet
Author: User
Tags addall

I believe everyone is RecyclerView familiar with the usage, and RecyclerView the advent of the show gives us the developer a highly extended control,
Whether it's a list, grid, waterfall flow, a control can be done, and the magic is 只需要修改一行代码,就可以轻松切换 . Too many benefits too much RecyclerView , do not list, there are a lot RecyclerView of tutorials on the web. Speaking of this, we began to enter the theme, although there are so many tutorials on the web, RecyclerView but not a detailed description RecyclerView of the animation, most of the use of the default DefaultItemAnimator or use a third-party animation library, this blog we will make up this gap, we come to the basis DefaultItemAnimator of Code to implement a simple RecyclerView animation.

We just go to achieve the most commonly used add and remove animation, other animations, if you are interested, you can refer DefaultItemAnimator to the extension.

Before we start, let's take a look at the effect of the implementation:

How do I customize the animation? The first thing to inherit from this class is that since we are RecyclerView.ItemAnimator going to inherit this class, it is necessary to look at the class and some of the methods in this class (just focus on what we need today, other similarities).

This class defines the animations, the take place on items as changes is made to the adapter. Subclasses of Itemanimator can is used to implement custom animations for actions on viewholder items. The Recyclerview would manage retaining these items while they is being animated, but Implementors must call the Appropria TE "Starting" (Dispatchremovestarting (Viewholder), dispatchmovestarting (Viewholder), dispatchchangestarting ( Viewholder, Boolean), or dispatchaddstarting (Viewholder)) and "Finished" (Dispatchremovefinished (Viewholder), Dispatchmovefinished (Viewholder), Dispatchchangefinished (Viewholder, Boolean), or dispatchaddfinished (ViewHolder)) Methods when the item animation is being started and ended.

Just look at the focus, when the animation starts, we need to call dispatchXXXStarting() , when the animation ends, we need to call dispatchXXXFinished() .
Next, take a look at some of the ways we need to do this:

    1. IsRunning ()

      Returns whether there is currently an animation to be performed.

    2. runpendinganimations ()

      Called when an animation is to be performed. It is important to note that when we go to add an item, the animation may not be executed immediately, and this mechanism allows Itemanimator to add and then execute it.

    3. Animateadd ()

      Add animation when we call Adapter.notifyiteminsert () fires the method, which has a Boolean return value that indicates whether runpendinganimations can be executed at the next opportunity. So when we customize the animation, this method returns True.

    4. Similar to Animateadd also has animatemove , animateremove , Animatechange .

    5. dispatchaddstarting ()

      is called at the beginning of the animation.

    6. dispatchaddfinished ()

      Animation at the end of the call.

    7. dispatchanimationsfinished ()

      All animations are called at the end.

Well, the introduction of a few uses of the method, the following to achieve our own animation bar. Or the animation above that we only implement add and remove . DefaultItemAnimatorwe need 4 of them to imitate the calculations ArrayList .

private ArrayList<RecyclerView.ViewHolder> mPendingAddHolders =                new ArrayList<>();private ArrayList<RecyclerView.ViewHolder> mPendingRemoveHolders =                new ArrayList<>();privatenew ArrayList<>();privatenew ArrayList<>();

Clearly on the two animation, how to need 4? ArrayList And it's a pair! Envy not? This is a good place to say. It says, the animation may not be executed immediately, but in a runPendingAnimations piece to execute, so we are in animateAdd , just mPendingAddHolders add one to the ViewHolder , not to write the animation code. At this point, consider a situation where:

When we animateAdd had a time when runPendingAnimations the animation was not finished, so we can not clear mPendingAddHolders the collection, then the execution of a time animateAdd what will happen? The previous one repeated the animation, in the DefaultItemAnimator smart to solve the problem, and the above 4 variables, in the following code, we will also learn this way to achieve.

Before starting the code, let's take isRunning a look at how this method should be written.

@OverridepublicbooleanisRunning() {  return !(mPendingAddHolders.isEmpty()                    && mPendingRemoveHolders.isEmpty()                    && mAddAnimtions.isEmpty()                    && mRemoveAnimations.isEmpty());}

Not much to say, only a word: isRunning not that there is no animation to do it.

That continues the code, to look at animateAdd and animateRemove How the method is written.

@OverridepublicbooleananimateAdd(RecyclerView.ViewHolder holder) {    holder.itemView.setAlpha(0.f);    mPendingAddHolders.add(holder);    returntrue;}@OverridepublicbooleananimateRemove(RecyclerView.ViewHolder holder) {    mPendingRemoveHolders.add(holder);    returntrue;}

It says, here we simply add a holder to the collection and set the return value to true be executed runPendingAnimations . It is important to note that the animateAdd first line of code for the method, we will not see the view settings, so that the purpose is to prevent the item flashing (before the animation is performed).

Then there's the next thing: runPendingAnimations :

@Override Public void runpendinganimations() {BooleanIsremove =!mpendingremoveholders.isempty ();BooleanIsadd =!mpendingaddholders.isempty ();if(!isremove &&!isadd)return;//First remove    if(Isremove) { for(Recyclerview.viewholder holder:mpendingremoveholders)        {Animateremoveimpl (holder);    } mpendingremoveholders.clear (); }//Last add    if(Isadd) {Arraylist<recyclerview.viewholder> holders =NewArraylist<> ();        Holders.addall (mpendingaddholders); Mpendingaddholders.clear (); for(Recyclerview.viewholder holder:holders)        {Animateaddimpl (holder);    } holders.clear (); }}

To explain the code, first two variables to determine whether the two pending collection is not empty, this determines whether our code needs to be executed down. And then to Judge isRemove , in this, to perform remove the animation,
As you can see, we iterate through each of the saved Viewholder, then go to execute the animateRemoveImpl method and finally mPendingRemoveHolders empty.
animateRemoveImplLet's go ahead and take a look add , here we first mPendingAddHolders add all the holder to a local list, then empty it,
The purpose of this is to prevent the animation from being repeated, and then, as with remove, to traverse all the holder execution animateAddImpl methods, and finally, to empty the local list.
And then, we're going to look at the animateRemoveImpl animateAddImpl method, and these two methods are the place to actually do the animation.

//Perform add animationPrivate void Animateaddimpl(FinalRecyclerview.viewholder holder) {maddanimtions.add (holder);FinalView item = Holder.itemview; Objectanimator animator = Objectanimator.offloat (item,"Alpha",0.F1.f); Animator.setduration ( +); Animator.addlistener (NewAnimatorlisteneradapter () {@Override         Public void Onanimationstart(Animator animation)        {dispatchaddstarting (holder); }@Override         Public void Onanimationcancel(Animator animation) {Item.setalpha (1.f); }@Override         Public void Onanimationend(Animator animation)            {dispatchaddfinished (holder); Maddanimtions.remove (holder);if(!isrunning ()) dispatchanimationsfinished ();    }    }); Animator.start ();}//Perform a move-out animationPrivate void Animateremoveimpl(FinalRecyclerview.viewholder holder) {mremoveanimations.add (holder);FinalView item = Holder.itemview; Objectanimator animator = Objectanimator.offloat (item,"Alpha",1.F0.f); Animator.setduration ( +); Animator.addlistener (NewAnimatorlisteneradapter () {@Override         Public void Onanimationstart(Animator animation)        {dispatchremovestarting (holder); }@Override         Public void Onanimationend(Animator animation)            {mremoveanimations.remove (holder); Item.setalpha (1.f); dispatchremovefinished (holder);if(!isrunning ()) dispatchanimationsfinished ();    }    }); Animator.start ();}

You can see that these two methods are very similar, so we just say one of them, well, just say the one that's closest to me animateRemoveImpl .
First add this holder to mRemoveAnimations , and then a very familiar property animation, here we just change the value of Itemview in the animation, alpha
We call the method at the beginning of the animation in the document, dispatchRemoveStarting at the end of the animation call dispatchRemoveFinished method, and finally to determine whether there is no execution of the animation,
If not, call dispatchAddFinished . Everything that is done here is in accordance with the rules of the document.

So excited, finally realized RecyclerView the animation, to use our Itemanimator

...mRecyclerView.setAdapter(mAdapter);mRecyclerView.setItemAnimator(new MyItemAnimator());

Look at the effect:

From the effect can be seen, our add animation is no problem, but the remove animation cliff is not the effect we want!! It's too ... it.
Well, after careful observation of the 1min effect, I finally found that the problem lies, secretly told you:

When we remove, does the following item move up? Moved, is that the way to execute it animateMove ?

So, we also need move a set of processes.
First, add a pair of sets.

private ArrayList<MoveInfo> mPendingMoveHolders =                new ArrayList<>();privatenew ArrayList<>();

Another pair of good friends, oh, no, it's a good couple.
Hey MoveInfo , what's this? Think carefully about a moving process that is not needed to know 来自哪里,将要去何方 . We imitate DefaultItemAnimator to define an inner class MoveInfo .

Class Moveinfo {PrivateRecyclerview.viewholder Holder;Private intFromX;Private intFromY;Private intToX;Private intToY; Public Moveinfo(Recyclerview.viewholder holder,intFromX,intFromY,intToX,intToY) { This. Holder = Holder; This. FromX = FromX; This. FromY = FromY; This. ToX = ToX; This. ToY = ToY; }}

Well, there is nothing to say, then continue to look at the animateMove method, it must be added to the mPendingMoveHolders one, but here is the addition of one MoveInfo .

 @Override  public  boolean   Animatemove  (recyclerview.viewholder holder, int  FromX, int  FromY, int  ToX,    int  ToY) {View view = Holder.itemview;    FromY + = View.gettranslationy ();    int  delta = toy-fromy;    View.settranslationy (-delta);    Moveinfo info = new  moveinfo (Holder, FromX, FromY, ToX, ToY);    Mpendingmoveholders.add (info); return  true ;}  

It is worth mentioning that int delta = toY - fromY we have to calculate the distance to change the view to move, and then take the reverse plug view.translationY ,
The purpose of this is to get the top one in the process of moving out, the following item does not move up immediately. Instead, offset a certain distance.
Here for good understanding, we print a set of values to help me understand

FROMY:20, toy:0
Delta:-20
Translationy:20

So in this scenario, you first move the view down by 20 pixels, and the effect is that it does not move in its original position.
Go down, construct one MoveInfo and add it to the mPendingMoveHolders inside.

Continue to modify the runPendingAnimations method, add our move operation, this part add of the code is very similar to the code, can be copied to modify the changes.

@Override Public void runpendinganimations() {BooleanIsremove =!mpendingremoveholders.isempty ();BooleanIsmove =!mpendingmoveholders.isempty ();BooleanIsadd =!mpendingaddholders.isempty ();if(!isremove &&!ismove &&!isadd)return; ...//Then move    if(Ismove) {arraylist<moveinfo> Infos =NewArraylist<> ();        Infos.addall (mpendingmoveholders); Mpendingmoveholders.clear (); for(Moveinfo Info:infos)        {Animatemoveimpl (info);    } infos.clear (); }    ...//Last add}

You can see that our move is completely a copy of the add, if you do not understand, you can turn online blog, see the Add section of the description.
Continue to come to the animateMoveImpl method.

//Perform motion animationsPrivate void Animatemoveimpl(FinalMoveinfo info) {Mmoveanimtions.remove (info);FinalView view = Info.holder.itemView; Objectanimator animator = objectanimator.offloat (view,"Translationy", View.gettranslationy (),0); Animator.setduration ( +); Animator.addlistener (NewAnimatorlisteneradapter () {@Override         Public void Onanimationstart(Animator animation)        {dispatchmovestarting (Info.holder); }@Override         Public void Onanimationend(Animator animation)            {dispatchmovefinished (Info.holder); Mmoveanimtions.remove (Info.holder);if(!isrunning ()) dispatchanimationsfinished ();    }    }); Animator.start ();}

In this we construct an translationY animation, the effect is from the view current offset to 0 of a constant offset effect. To put it bluntly is the effect of continuous upward. The processing and add are the same logic at the beginning and end of the animation.

Now the code is finally finished, the effect is the beginning of the blog effect.

Said, to the present we only have not achieved the effect of the effect is change , in fact, the change processing and move processing is very similar,
Interested friends can refer to DefaultItemAnimator the source code.
It seems that it is RecyclerView not so complicated to implement an item animation yourself, but there is a lot of code, is it not that we need to write this long code every time? Of course not! Watch the code carefully,
In fact, the implementation of the animation is animateXXXImpl implemented in, we can completely aninateXXXImpl abstract out, need what animation, we inherit this class, just to achieve aninateXXXImpl the
Code can, of course, others have provided us with a lot of animation library, we can not write on their own, directly use the three-side. Here's a great RecyclerView library of animations to do,
Direct copy to the project can be used.

Recyclerview Item Animation Library on GitHub

At the end of the demo:
Demo Download, Poke here

Note: The property animation in the demo, if you need backward compatibility, can be swapped nineoldandroids or ViewCompat implemented.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Advanced usage of Recyclerview-custom animations

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.