Android RecyclerView的Item自定义动画及DefaultItemAnimator源码分析_Android

这是关于RecyclerView的第二篇,说的是如何自定义Item动画,但是请注意,本文不包含动画的具体实现方法,只是告诉大家如何去自定义动画,如何去参考源代码。 

我们知道,RecyclerView默认会使用DefaultItemAnimator,所以如果我们需要自定义动画,那么应该好好的读读这个类的源代码,这样不仅仅是学习怎么自定义,还要学习Android的设计模式。 

先弄明白一件事,DefaultItemAnimator继承自SimpleItemAnimator,SimpleItemAnimator继承自RecyclerView.ItemAnimator,所以如果需要自定义动画,最简单的方法是继承SimpleItemAnimator。其次,动画的类型有四种,分别是Add、Remove、Move以及Change,这里我们只列举Remove,举一反三。 

我们先看SimpleItemAnimator中的源码,在SimpleItemAnimator中有几个重要的方法: 

@Override
 public boolean animateDisappearance(@NonNull ViewHolder viewHolder,
   @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
  int oldLeft = preLayoutInfo.left;
  int oldTop = preLayoutInfo.top;
  View disappearingItemView = viewHolder.itemView;
  int newLeft = postLayoutInfo == null ? disappearingItemView.getLeft() : postLayoutInfo.left;
  int newTop = postLayoutInfo == null ? disappearingItemView.getTop() : postLayoutInfo.top;
  if (!viewHolder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
   disappearingItemView.layout(newLeft, newTop,
     newLeft + disappearingItemView.getWidth(),
     newTop + disappearingItemView.getHeight());
   if (DEBUG) {
    Log.d(TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView);
   }
   return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop);
  } else {
   if (DEBUG) {
    Log.d(TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView);
   }
   return animateRemove(viewHolder);
  }
 }

解析:这个函数是重写RecyclerView.ItemAnimator的,接口中参数分别是ViewHolder、prelayoutInfo以及postLayoutInfo,第一个参数是指Item的ViewHolder,可以通过这个对象的itemView来获取它的View,第二个参数是指Item删除前的位置信息,第三个是指新的位置信息。再接下来会判断ViewHolder是否已经被移除以及位置是否发生变化,然后在调用animateRemove这个抽象方法,如果我们要自定义动画,就需要去实现它(回调思想)。

 public final void dispatchRemoveStarting(ViewHolder item) {
   onRemoveStarting(item);
 }
public void onRemoveStarting(ViewHolder item) {
 }

解析:dispatchRemoveStaring个是一个final方法,也就是不能被重写,如果我们需要处理一些在Remove开始的时候的逻辑,我们就需要在animateRemove方法中调用这个方法,这个方法会执行一个onRemoveStaring方法,这个方法就允许我们重写,所以逻辑应该写在onRemoveStaring中,当我们调用dispatchRemoveStaring的时候,onRemoveStaring就会被执行。 

这里只说了两个,但是,加上其他动作的就不只是两个啦。。。
所以,当我们继承了SimpleItemAnimator的时候,需要实现里面的一些方法,一般有如下这些: 
 ① animateRemove(Add、Move和Change):这些方法会在动画发生的时候回调,一般会在这个方法中用列表记录每个Item的动画以及属性
 ② endAnimation、endAnimations:分别是在一个Item或是多个Item需要立即停止的时候回调
 ③ isRunning:如果需要顺畅滑动的时候,必须要重写这个方法,很多时候比如在网络加载的时候滑动卡顿就是这个方法逻辑不对
 ④ run'PendingAnimations:这是最重要的一个方法。因为animateDisappearence等方法返回的是animateRemove等方法返回的值,而这个方法则是根据这些值来确定是否有准备好的动画需要播放,如果有,就会回调这个方法。在这个方法我们需要处理每一个动作(Remove、Add、Move以及Change)的动画
 

所以,我们的一般步骤就是:
 ①创建一个SimpleItemAnimator的子类
 ②创建每个动作的动作列表
 ③重写animateRemove等方法,当界面中有动作发生,这些函数会被回调,这里进行记录并返回true使得run'PendingAnimations开始执行
 ④重写run'PendingAnimations,当③的方法返回true的时候,就认为需要执行动画,我们需要把动画执行的逻辑写在这里面
 ⑤重写isRunning,提供动画播放状态,一般是返回动作列表是否为空
 ⑥如果有需要,重写endAnimation、endAnimations、onRemoveFinish等方法
具体的步骤有了,但是我们还不清楚该怎么构建它,不用着急,为了方便我们,谷歌其实已经提供了DefaultItemAnimator,我们可以参考一些它的源码,没有人讲的比源码有道理,我们需要的是有足够的耐心!
DefaultItemAnimator中定义了一些ArrayList来存放动作的信息,如下:

 private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();

@Override
 public boolean animateRemove(final ViewHolder holder) {
  resetAnimation(holder);
  mPendingRemovals.add(holder);
  return true;
 }

解析:可以看到animatorRemove方法直接是把viewholder加入列表中,然后返回true 

@Override
 public void runPendingAnimations() {
  boolean removalsPending = !mPendingRemovals.isEmpty();
  boolean movesPending = !mPendingMoves.isEmpty();
  boolean changesPending = !mPendingChanges.isEmpty();
  boolean additionsPending = !mPendingAdditions.isEmpty();
  if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
   // nothing to animate
   return;
  }
  // First, remove stuff
  for (ViewHolder holder : mPendingRemovals) {
   animateRemoveImpl(holder);
  }
  mPendingRemovals.clear();
  // Next, move stuff
  ......
  // Next, change stuff, to run in parallel with move animations
  ......
  // Next, add stuff
  ......
 }

解析:根据上面可以知道,runPendingAnimations会执行,可看到,在这个方法中遍历了动作列表,并让每个Item都执行了animatorRemoveImpl方法,其他动作的方法暂时先省略,有兴趣的可以自行阅读。 

private void animateRemoveImpl(final ViewHolder holder) {
  final View view = holder.itemView;
  final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
  mRemoveAnimations.add(holder);
  animation.setDuration(getRemoveDuration())
    .alpha(0).setListener(new VpaListenerAdapter() {
   @Override
   public void onAnimationStart(View view) {
    dispatchRemoveStarting(holder);
   }

   @Override
   public void onAnimationEnd(View view) {
    animation.setListener(null);
    ViewCompat.setAlpha(view, 1);
    dispatchRemoveFinished(holder);
    mRemoveAnimations.remove(holder);
    dispatchFinishedWhenDone();
   }
  }).start();
 }

解析:可以看到animatorRemoveImpl方法中实现了整个动画的具体逻辑,具体怎么做不在本文范围中,在我们执行了动画之后,也就是在动画的Listener中的onAnimatorEnd中调用了dispatchRemoveFinish,还记得这个方法吗,它会执行onRemoveFinish方法,onRemoveFinish方法是可以供给我们重写的。然后把item移除动作列表。 

@Override
 public boolean isRunning() {
  return (!mPendingAdditions.isEmpty() ||
    !mPendingChanges.isEmpty() ||
    !mPendingMoves.isEmpty() ||
    !mPendingRemovals.isEmpty() ||
    !mMoveAnimations.isEmpty() ||
    !mRemoveAnimations.isEmpty() ||
    !mAddAnimations.isEmpty() ||
    !mChangeAnimations.isEmpty() ||
    !mMovesList.isEmpty() ||
    !mAdditionsList.isEmpty() ||
    !mChangesList.isEmpty());
 }

解析:isRunning方法其实就是根据动作列表是否为空来返回结果
还有其他一些函数可以自己阅读源代码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, item
, recyclerview
DefaultItemAnimator
defaultitemanimator、recyclerview删除item、recyclerview多种item、recyclerview获取item、recyclerview不同item,以便于您获取更多的相关知识。

时间: 2025-01-25 09:08:17

Android RecyclerView的Item自定义动画及DefaultItemAnimator源码分析_Android的相关文章

Android RecyclerView的Item自定义动画及DefaultItemAnimator源码分析

这是关于RecyclerView的第二篇,说的是如何自定义Item动画,但是请注意,本文不包含动画的具体实现方法,只是告诉大家如何去自定义动画,如何去参考源代码. 我们知道,RecyclerView默认会使用DefaultItemAnimator,所以如果我们需要自定义动画,那么应该好好的读读这个类的源代码,这样不仅仅是学习怎么自定义,还要学习Android的设计模式. 先弄明白一件事,DefaultItemAnimator继承自SimpleItemAnimator,SimpleItemAnim

Android透明化和沉浸式状态栏实践及源码分析

本文所提到的透明状态栏其实指的是将顶部的导航栏延伸到状态栏,使之浑然一体(Google官方建议状态栏颜色比导航栏的颜色略深一点),并不代表一定不设置背景色,比如导航栏是白色,则可设置状态栏为白色,视情况而定. 相比于iOS系统,Android系统对于状态栏的设置就显得稍微复杂了一点.Android系统提供了API 19以上对状态栏的设置接口,而直到API 23以上才提供对于icon颜色的设置,还有就是各家厂商(如魅族,小米等)对于状态栏的有自己的定制,对于需要使用浅色背景状态栏的应用,没处理好的

Android AsyncTask源码分析_Android

Android中只能在主线程中进行UI操作,如果是其它子线程,需要借助异步消息处理机制Handler.除此之外,还有个非常方便的AsyncTask类,这个类内部封装了Handler和线程池.本文先简要介绍AsyncTask的用法,然后分析具体实现. 基本用法AsyncTask是一个抽象类,我们需要创建子类去继承它,并且重写一些方法.AsyncTask接受三个泛型参数: Params: 指定传给任务执行时的参数的类型 Progress: 指定后台任务执行时将任务进度返回给UI线程的参数类型 Res

Android点击事件派发机制源码分析_Android

概述  一直想写篇关于Android事件派发机制的文章,却一直没写,这两天刚好是周末,有时间了,想想写一篇吧,不然总是只停留在会用的层次上但是无法了解其内部机制.我用的是4.4源码,打开看看,挺复杂的,尤其是事件是怎么从Activity派发出来的,太费解了.了解Windows消息机制的人会发现,觉得Android的事件派发机制和Windows的消息派发机制挺像的,其实这是一种典型的消息"冒泡"机制,很多平台采用这个机制,消息最先到达最底层View,然后它先进行判断是不是它所需要的,否则

Android Handler消息派发机制源码分析_Android

注:这里只是说一下sendmessage的一个过程,post就类似的 如果我们需要发送消息,会调用sendMessage方法 public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } 这个方法会调用如下的这个方法  public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMill

Jquery1.9.1源码分析系列(十五)动画处理之外篇_jquery

a.动画兼容Tween.propHooks Tween.propHooks提供特殊情况下设置.获取css特征值的方法,结构如下 Tween.propHooks = { _default: { get: function(){...}, set: function(){...} }, scrollTop: { set: function(){...} } scrollLeft: { set: function(){...} } } Tween.propHooks.scrollTop 和Tween.

自定义View系列教程04--Draw源码分析及其实践

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View

从源码分析Android的Glide库的图片加载流程及特点_Android

0.基础知识Glide中有一部分单词,我不知道用什么中文可以确切的表达出含义,用英文单词可能在行文中更加合适,还有一些词在Glide中有特别的含义,我理解的可能也不深入,这里先记录一下. (1)View: 一般情况下,指Android中的View及其子类控件(包括自定义的),尤其指ImageView.这些控件可在上面绘制Drawable (2)Target: Glide中重要的概念,目标.它即可以指封装了一个View的Target(ViewTarget),也可以不包含View(SimpleTar

基于JS快速实现导航下拉菜单动画效果附源码下载_javascript技巧

这是一个带变形动画特效的下拉导航菜单特效.该导航菜单在菜单项之间切换时,下拉菜单会快速的根据菜单内容的大小来动态变形,显示合适的下拉菜单大小,效果非常棒. 快速的导航下拉菜单动画效果如下所示: 效果演示         源码下载 HTML 该导航菜单的HTML结构如下: <header class="cd-morph-dropdown"> <a href="#0" class="nav-trigger">Open Nav&