public abstract static class RecyclerView.ItemAnimator extends Object
#dispatchAnimationFinished(ViewHolder)
when a ViewHolder's animation is finished. In other words, there must be a matching
#dispatchAnimationFinished(ViewHolder)
call for each
animateAppearance()
,
animateChange()
animatePersistence()
,
and
animateDisappearance()
call.
By default, RecyclerView uses DefaultItemAnimator
.
Modifier and Type | Class and Description |
---|---|
static interface |
RecyclerView.ItemAnimator.AdapterChanges
The set of flags that might be passed to
#recordPreLayoutInformation(State, ViewHolder, int, List) . |
static interface |
RecyclerView.ItemAnimator.ItemAnimatorFinishedListener
This interface is used to inform listeners when all pending or running animations
in an ItemAnimator are finished.
|
static class |
RecyclerView.ItemAnimator.ItemHolderInfo
A simple data structure that holds information about an item's bounds.
|
Modifier and Type | Field and Description |
---|---|
static int |
FLAG_APPEARED_IN_PRE_LAYOUT
This ViewHolder was not laid out but has been added to the layout in pre-layout state
by the
RecyclerView.LayoutManager . |
static int |
FLAG_CHANGED
The Item represented by this ViewHolder is updated.
|
static int |
FLAG_INVALIDATED
Adapter
RecyclerView.Adapter.notifyDataSetChanged() has been called and the content
represented by this ViewHolder is invalid. |
static int |
FLAG_MOVED
The position of the Item represented by this ViewHolder has been changed.
|
static int |
FLAG_REMOVED
The Item represented by this ViewHolder is removed from the adapter.
|
Constructor and Description |
---|
ItemAnimator() |
Modifier and Type | Method and Description |
---|---|
abstract boolean |
animateAppearance(RecyclerView.ViewHolder viewHolder,
RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo,
RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
Called by the RecyclerView when a ViewHolder is added to the layout.
|
abstract boolean |
animateChange(RecyclerView.ViewHolder oldHolder,
RecyclerView.ViewHolder newHolder,
RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo,
RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
Called by the RecyclerView when an adapter item is present both before and after the
layout and RecyclerView has received a
RecyclerView.Adapter.notifyItemChanged(int) call
for it. |
abstract boolean |
animateDisappearance(RecyclerView.ViewHolder viewHolder,
RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo,
RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
Called by the RecyclerView when a ViewHolder has disappeared from the layout.
|
abstract boolean |
animatePersistence(RecyclerView.ViewHolder viewHolder,
RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo,
RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
Called by the RecyclerView when a ViewHolder is present in both before and after the
layout and RecyclerView has not received a
RecyclerView.Adapter.notifyItemChanged(int) call
for it or a RecyclerView.Adapter.notifyDataSetChanged() call. |
boolean |
canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder)
When an item is changed, ItemAnimator can decide whether it wants to re-use
the same ViewHolder for animations or RecyclerView should create a copy of the
item and ItemAnimator will use both to run the animation (e.g. cross-fade).
|
boolean |
canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder,
List<Object> payloads)
When an item is changed, ItemAnimator can decide whether it wants to re-use
the same ViewHolder for animations or RecyclerView should create a copy of the
item and ItemAnimator will use both to run the animation (e.g. cross-fade).
|
void |
dispatchAnimationFinished(RecyclerView.ViewHolder viewHolder)
Method to be called by subclasses when an animation is finished.
|
void |
dispatchAnimationsFinished()
This method should be called by ItemAnimator implementations to notify
any listeners that all pending and active item animations are finished.
|
void |
dispatchAnimationStarted(RecyclerView.ViewHolder viewHolder)
Method to be called by subclasses when an animation is started.
|
abstract void |
endAnimation(RecyclerView.ViewHolder item)
Method called when an animation on a view should be ended immediately.
|
abstract void |
endAnimations()
Method called when all item animations should be ended immediately.
|
long |
getAddDuration()
Gets the current duration for which all add animations will run.
|
long |
getChangeDuration()
Gets the current duration for which all change animations will run.
|
long |
getMoveDuration()
Gets the current duration for which all move animations will run.
|
long |
getRemoveDuration()
Gets the current duration for which all remove animations will run.
|
abstract boolean |
isRunning()
Method which returns whether there are any item animations currently running.
|
boolean |
isRunning(RecyclerView.ItemAnimator.ItemAnimatorFinishedListener listener)
Like
isRunning() , this method returns whether there are any item
animations currently running. |
RecyclerView.ItemAnimator.ItemHolderInfo |
obtainHolderInfo()
Returns a new
RecyclerView.ItemAnimator.ItemHolderInfo which will be used to store information about the
ViewHolder. |
void |
onAnimationFinished(RecyclerView.ViewHolder viewHolder)
Called after
#dispatchAnimationFinished(ViewHolder) is called by the
ItemAnimator. |
void |
onAnimationStarted(RecyclerView.ViewHolder viewHolder)
Called when a new animation is started on the given ViewHolder.
|
RecyclerView.ItemAnimator.ItemHolderInfo |
recordPostLayoutInformation(RecyclerView.State state,
RecyclerView.ViewHolder viewHolder)
Called by the RecyclerView after the layout is complete.
|
RecyclerView.ItemAnimator.ItemHolderInfo |
recordPreLayoutInformation(RecyclerView.State state,
RecyclerView.ViewHolder viewHolder,
int changeFlags,
List<Object> payloads)
Called by the RecyclerView before the layout begins.
|
abstract void |
runPendingAnimations()
Called when there are pending animations waiting to be started.
|
void |
setAddDuration(long addDuration)
Sets the duration for which all add animations will run.
|
void |
setChangeDuration(long changeDuration)
Sets the duration for which all change animations will run.
|
void |
setMoveDuration(long moveDuration)
Sets the duration for which all move animations will run.
|
void |
setRemoveDuration(long removeDuration)
Sets the duration for which all remove animations will run.
|
public static final int FLAG_CHANGED
#recordPreLayoutInformation(State, ViewHolder, int, List)
,
Constant Field Valuespublic static final int FLAG_REMOVED
#recordPreLayoutInformation(State, ViewHolder, int, List)
,
Constant Field Valuespublic static final int FLAG_INVALIDATED
RecyclerView.Adapter.notifyDataSetChanged()
has been called and the content
represented by this ViewHolder is invalid.
#recordPreLayoutInformation(State, ViewHolder, int, List)
,
Constant Field Valuespublic static final int FLAG_MOVED
RecyclerView.Adapter.notifyItemMoved(int, int)
. It might be set in response to
any adapter change that may have a side effect on this item. (e.g. The item before this
one has been removed from the Adapter).
#recordPreLayoutInformation(State, ViewHolder, int, List)
,
Constant Field Valuespublic static final int FLAG_APPEARED_IN_PRE_LAYOUT
RecyclerView.LayoutManager
. This means that the item was already in the Adapter but
invisible and it may become visible in the post layout phase. LayoutManagers may prefer
to add new items in pre-layout to specify their virtual location when they are invisible
(e.g. to specify the item should animate in from below the visible area).
#recordPreLayoutInformation(State, ViewHolder, int, List)
,
Constant Field Valuespublic long getMoveDuration()
public void setMoveDuration(long moveDuration)
moveDuration
- The move durationpublic long getAddDuration()
public void setAddDuration(long addDuration)
addDuration
- The add durationpublic long getRemoveDuration()
public void setRemoveDuration(long removeDuration)
removeDuration
- The remove durationpublic long getChangeDuration()
public void setChangeDuration(long changeDuration)
changeDuration
- The change duration@NonNull public RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state, @NonNull RecyclerView.ViewHolder viewHolder, int changeFlags, @NonNull List<Object> payloads)
The data returned from this method will be passed to the related animate**
methods.
Note that this method may be called after pre-layout phase if LayoutManager adds new Views to the layout in pre-layout pass.
The default implementation returns an RecyclerView.ItemAnimator.ItemHolderInfo
which holds the bounds of
the View and the adapter change flags.
state
- The current State of RecyclerView which includes some useful data
about the layout that will be calculated.viewHolder
- The ViewHolder whose information should be recorded.changeFlags
- Additional information about what changes happened in the Adapter
about the Item represented by this ViewHolder. For instance, if
item is deleted from the adapter, FLAG_REMOVED
will be set.payloads
- The payload list that was previously passed to
RecyclerView.Adapter.notifyItemChanged(int, Object)
or
RecyclerView.Adapter.notifyItemRangeChanged(int, int, Object)
.animate**
methods
after layout is complete.#recordPostLayoutInformation(State, ViewHolder)
,
#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
,
#animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
,
#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
,
#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
@NonNull public RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state, @NonNull RecyclerView.ViewHolder viewHolder)
The data returned from this method will be passed to the related animate**
methods.
The default implementation returns an RecyclerView.ItemAnimator.ItemHolderInfo
which holds the bounds of
the View.
state
- The current State of RecyclerView which includes some useful data about
the layout that will be calculated.viewHolder
- The ViewHolder whose information should be recorded.animate**
methods when
RecyclerView decides how items should be animated.#recordPreLayoutInformation(State, ViewHolder, int, List)
,
#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
,
#animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
,
#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
,
#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
public abstract boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo, @Nullable RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
This means that the View was a child of the LayoutManager when layout started but has
been removed by the LayoutManager. It might have been removed from the adapter or simply
become invisible due to other factors. You can distinguish these two cases by checking
the change flags that were passed to
#recordPreLayoutInformation(State, ViewHolder, int, List)
.
Note that when a ViewHolder both changes and disappears in the same layout pass, the
animation callback method which will be called by the RecyclerView depends on the
ItemAnimator's decision whether to re-use the same ViewHolder or not, and also the
LayoutManager's decision whether to layout the changed version of a disappearing
ViewHolder or not. RecyclerView will call
animateChange
instead of animateDisappearance
if and only if the ItemAnimator
returns false
from
canReuseUpdatedViewHolder
and the
LayoutManager lays out a new disappearing view that holds the updated information.
Built-in LayoutManagers try to avoid laying out updated versions of disappearing views.
If LayoutManager supports predictive animations, it might provide a target disappear
location for the View by laying it out in that location. When that happens,
RecyclerView will call #recordPostLayoutInformation(State, ViewHolder)
and the
response of that call will be passed to this method as the postLayoutInfo
.
ItemAnimator must call #dispatchAnimationFinished(ViewHolder)
when the animation
is complete (or instantly call #dispatchAnimationFinished(ViewHolder)
if it
decides not to animate the view).
viewHolder
- The ViewHolder which should be animatedpreLayoutInfo
- The information that was returned from
#recordPreLayoutInformation(State, ViewHolder, int, List)
.postLayoutInfo
- The information that was returned from
#recordPostLayoutInformation(State, ViewHolder)
. Might be
null if the LayoutManager did not layout the item.runPendingAnimations()
is requested,
false otherwise.public abstract boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder, @Nullable RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo, @NonNull RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
In detail, this means that the ViewHolder was not a child when the layout started but has been added by the LayoutManager. It might be newly added to the adapter or simply become visible due to other factors.
ItemAnimator must call #dispatchAnimationFinished(ViewHolder)
when the animation
is complete (or instantly call #dispatchAnimationFinished(ViewHolder)
if it
decides not to animate the view).
viewHolder
- The ViewHolder which should be animatedpreLayoutInfo
- The information that was returned from
#recordPreLayoutInformation(State, ViewHolder, int, List)
.
Might be null if Item was just added to the adapter or
LayoutManager does not support predictive animations or it could
not predict that this ViewHolder will become visible.postLayoutInfo
- The information that was returned from #recordPreLayoutInformation(State, ViewHolder, int, List)
.runPendingAnimations()
is requested,
false otherwise.public abstract boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo, @NonNull RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
RecyclerView.Adapter.notifyItemChanged(int)
call
for it or a RecyclerView.Adapter.notifyDataSetChanged()
call.
This ViewHolder still represents the same data that it was representing when the layout started but its position / size may be changed by the LayoutManager.
If the Item's layout position didn't change, RecyclerView still calls this method because
it does not track this information (or does not necessarily know that an animation is
not required). Your ItemAnimator should handle this case and if there is nothing to
animate, it should call #dispatchAnimationFinished(ViewHolder)
and return
false
.
ItemAnimator must call #dispatchAnimationFinished(ViewHolder)
when the animation
is complete (or instantly call #dispatchAnimationFinished(ViewHolder)
if it
decides not to animate the view).
viewHolder
- The ViewHolder which should be animatedpreLayoutInfo
- The information that was returned from
#recordPreLayoutInformation(State, ViewHolder, int, List)
.postLayoutInfo
- The information that was returned from #recordPreLayoutInformation(State, ViewHolder, int, List)
.runPendingAnimations()
is requested,
false otherwise.public abstract boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull RecyclerView.ViewHolder newHolder, @NonNull RecyclerView.ItemAnimator.ItemHolderInfo preLayoutInfo, @NonNull RecyclerView.ItemAnimator.ItemHolderInfo postLayoutInfo)
RecyclerView.Adapter.notifyItemChanged(int)
call
for it. This method may also be called when
RecyclerView.Adapter.notifyDataSetChanged()
is called and adapter has stable ids so that
RecyclerView could still rebind views to the same ViewHolders. If viewType changes when
RecyclerView.Adapter.notifyDataSetChanged()
is called, this method will not be called,
instead, #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
will be
called for the new ViewHolder and the old one will be recycled.
If this method is called due to a RecyclerView.Adapter.notifyDataSetChanged()
call, there is
a good possibility that item contents didn't really change but it is rebound from the
adapter. DefaultItemAnimator
will skip animating the View if its location on the
screen didn't change and your animator should handle this case as well and avoid creating
unnecessary animations.
When an item is updated, ItemAnimator has a chance to ask RecyclerView to keep the
previous presentation of the item as-is and supply a new ViewHolder for the updated
presentation (see: #canReuseUpdatedViewHolder(ViewHolder, List)
.
This is useful if you don't know the contents of the Item and would like
to cross-fade the old and the new one (DefaultItemAnimator
uses this technique).
When you are writing a custom item animator for your layout, it might be more performant and elegant to re-use the same ViewHolder and animate the content changes manually.
When RecyclerView.Adapter.notifyItemChanged(int)
is called, the Item's view type may change.
If the Item's view type has changed or ItemAnimator returned false
for
this ViewHolder when #canReuseUpdatedViewHolder(ViewHolder, List)
was called, the
oldHolder
and newHolder
will be different ViewHolder instances
which represent the same Item. In that case, only the new ViewHolder is visible
to the LayoutManager but RecyclerView keeps old ViewHolder attached for animations.
ItemAnimator must call #dispatchAnimationFinished(ViewHolder)
for each distinct
ViewHolder when their animation is complete
(or instantly call #dispatchAnimationFinished(ViewHolder)
if it decides not to
animate the view).
If oldHolder and newHolder are the same instance, you should call
#dispatchAnimationFinished(ViewHolder)
only once.
Note that when a ViewHolder both changes and disappears in the same layout pass, the
animation callback method which will be called by the RecyclerView depends on the
ItemAnimator's decision whether to re-use the same ViewHolder or not, and also the
LayoutManager's decision whether to layout the changed version of a disappearing
ViewHolder or not. RecyclerView will call
animateChange
instead of
animateDisappearance
if and only if the ItemAnimator returns false
from
canReuseUpdatedViewHolder
and the
LayoutManager lays out a new disappearing view that holds the updated information.
Built-in LayoutManagers try to avoid laying out updated versions of disappearing views.
oldHolder
- The ViewHolder before the layout is started, might be the same
instance with newHolder.newHolder
- The ViewHolder after the layout is finished, might be the same
instance with oldHolder.preLayoutInfo
- The information that was returned from
#recordPreLayoutInformation(State, ViewHolder, int, List)
.postLayoutInfo
- The information that was returned from #recordPreLayoutInformation(State, ViewHolder, int, List)
.runPendingAnimations()
is requested,
false otherwise.public abstract void runPendingAnimations()
animateAppearance()
,
animateChange()
animatePersistence()
, and
animateDisappearance()
, which inform the RecyclerView that the ItemAnimator wants to be
called later to start the associated animations. runPendingAnimations() will be scheduled
to be run on the next frame.public abstract void endAnimation(RecyclerView.ViewHolder item)
#dispatchAnimationFinished(ViewHolder)
should be called for each finished
animation since the animations are effectively done when this method is called.item
- The item for which an animation should be stopped.public abstract void endAnimations()
#dispatchAnimationFinished(ViewHolder)
should be called for each finished
animation since the animations are effectively done when this method is called.public abstract boolean isRunning()
public final void dispatchAnimationFinished(RecyclerView.ViewHolder viewHolder)
For each call RecyclerView makes to
animateAppearance()
,
animatePersistence()
, or
animateDisappearance()
, there
should
be a matching #dispatchAnimationFinished(ViewHolder)
call by the subclass.
For animateChange()
, subclass should call this method for both the oldHolder
and newHolder
(if they are not the same instance).
viewHolder
- The ViewHolder whose animation is finished.#onAnimationFinished(ViewHolder)
public void onAnimationFinished(RecyclerView.ViewHolder viewHolder)
#dispatchAnimationFinished(ViewHolder)
is called by the
ItemAnimator.viewHolder
- The ViewHolder whose animation is finished. There might still be other
animations running on this ViewHolder.#dispatchAnimationFinished(ViewHolder)
public final void dispatchAnimationStarted(RecyclerView.ViewHolder viewHolder)
For each call RecyclerView makes to
animateAppearance()
,
animatePersistence()
, or
animateDisappearance()
, there should be a matching
#dispatchAnimationStarted(ViewHolder)
call by the subclass.
For animateChange()
, subclass should call this method for both the oldHolder
and newHolder
(if they are not the same instance).
If your ItemAnimator decides not to animate a ViewHolder, it should call
#dispatchAnimationFinished(ViewHolder)
without calling
#dispatchAnimationStarted(ViewHolder)
.
viewHolder
- The ViewHolder whose animation is starting.#onAnimationStarted(ViewHolder)
public void onAnimationStarted(RecyclerView.ViewHolder viewHolder)
viewHolder
- The ViewHolder which started animating. Note that the ViewHolder
might already be animating and this might be another animation.#dispatchAnimationStarted(ViewHolder)
public final boolean isRunning(RecyclerView.ItemAnimator.ItemAnimatorFinishedListener listener)
isRunning()
, this method returns whether there are any item
animations currently running. Additionally, the listener passed in will be called
when there are no item animations running, either immediately (before the method
returns) if no animations are currently running, or when the currently running
animations are finished
.
Note that the listener is transient - it is either called immediately and not stored at all, or stored only until it is called when running animations are finished sometime later.
listener
- A listener to be called immediately if no animations are running
or later when currently-running animations have finished. A null listener is
equivalent to calling isRunning()
.public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder)
Note that this method will only be called if the RecyclerView.ViewHolder
still has the same
type (RecyclerView.Adapter.getItemViewType(int)
). Otherwise, ItemAnimator will always receive
both RecyclerView.ViewHolder
s in the
#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
method.
If your application is using change payloads, you can override
#canReuseUpdatedViewHolder(ViewHolder, List)
to decide based on payloads.
viewHolder
- The ViewHolder which represents the changed item's old content.true
.#canReuseUpdatedViewHolder(ViewHolder, List)
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads)
Note that this method will only be called if the RecyclerView.ViewHolder
still has the same
type (RecyclerView.Adapter.getItemViewType(int)
). Otherwise, ItemAnimator will always receive
both RecyclerView.ViewHolder
s in the
#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
method.
viewHolder
- The ViewHolder which represents the changed item's old content.payloads
- A non-null list of merged payloads that were sent with change
notifications. Can be empty if the adapter is invalidated via
RecyclerView.Adapter.notifyDataSetChanged()
. The same list of
payloads will be passed into
RecyclerView.Adapter#onBindViewHolder(ViewHolder, int, List)
method if this method returns true
.RecyclerView.canReuseUpdatedViewHolder(ViewHolder)
.RecyclerView.canReuseUpdatedViewHolder(ViewHolder)
public final void dispatchAnimationsFinished()
public RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo()
RecyclerView.ItemAnimator.ItemHolderInfo
which will be used to store information about the
ViewHolder. This information will later be passed into animate**
methods.
You can override this method if you want to extend RecyclerView.ItemAnimator.ItemHolderInfo
and provide
your own instances.
RecyclerView.ItemAnimator.ItemHolderInfo
.