iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android RecyclerView的Item自定义动画及DefaultItemAnimator源码分析
  • 857
分享到

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

recyclerview动画Android 2022-06-06 08:06:15 857人浏览 泡泡鱼
摘要

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

这是关于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中RecyclerView点击Item设置事件Android RecyclerView选择多个item的实现代码Android RecyclerView的Item点击事件实现整理Android 中RecyclerView多种item布局的写法(头布局+脚布局)android RecyclerView实现条目Item拖拽排序与滑动删除android使用ItemDecoration给RecyclerView 添加水印Android RecyclerView显示Item布局不一致解决办法Android中RecyclerView的item宽高问题详解


--结束END--

本文标题: Android RecyclerView的Item自定义动画及DefaultItemAnimator源码分析

本文链接: https://www.lsjlt.com/news/24637.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android深入分析属性动画源码
    1.先看一段动画的代码实现 ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1, 0,1); alpha.s...
    99+
    2024-04-02
  • Android自定义开关按钮源码解析
    本文实例为大家分享了Android自定义开关的具体代码,供大家参考,具体内容如下 以 ToggleColorY 为例分析, ToggleImageY逻辑代码差不多 初始化参数 获取背...
    99+
    2024-04-02
  • Vue.js源码分析之自定义指令的示例分析
    这篇文章给大家分享的是有关Vue.js源码分析之自定义指令的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令...
    99+
    2023-06-14
  • Vue组件中的自定义事件源码分析
    这篇文章主要介绍“Vue组件中的自定义事件源码分析”,在日常操作中,相信很多人在Vue组件中的自定义事件源码分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue组件中的自定义事件源码分析”的疑惑有所帮助!...
    99+
    2023-06-29
  • Vue.js源码分析之自定义指令详解
    前言 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。 官网介绍的比较抽象,显得很高大上,我个人对自定义指令的理解是:当自定义指令作用...
    99+
    2024-04-02
  • Android自定义View播放Gif动画的示例
    前言GIF是一种很常见的动态图片格式,在Android中它的使用场景非常多,大到启动页动画、小到一个Loading展示,都可以用GIF动画来完成,使用也很方便,直接从美工那边拿过来用就成。如果项目赶时间或者自定义原生动画太麻烦,GIF都是一...
    99+
    2023-05-30
    android 播放 gif
  • Flutter源码分析之自定义控件(RenderBox)指南
    目录前言RenderObject 类继承层级解析RenderBox叶节点与父节点控件的测量与布局performResize 和 performLayoutrelayoutBounda...
    99+
    2024-04-02
  • 详解Android如何实现自定义的动画曲线
    目录前言Curve 类定义实例解析正弦动画曲线总结前言 最近在写动画相关的篇章,经常会用到 Curve 这个动画曲线类,那这个类到底怎么实现的?如果想自己来一个自...
    99+
    2024-04-02
  • Android okhttp的启动流程及源码解析
    目录前言 什么是OKhttp OkHttp是如何做网络请求的 1.它是如何使用的? 1.1 通过构造者模式添加 url,method,header,body 等完成一个请求的信息 R...
    99+
    2024-04-02
  • SpringBoot2入门自动配置原理及源码分析
    目录SpringBoot自动配置一、@SpringBootApplication1. @SpringBootConfiguration2. @ComponentScan3. @Ena...
    99+
    2024-04-02
  • docker中资源指标API及自定义指标API的示例分析
    这篇文章给大家分享的是有关docker中资源指标API及自定义指标API的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。    以前是用heapster来收集资源指标才能看,现在hea...
    99+
    2023-06-04
  • Android自定义滑动验证条的示例代码
    本文介绍了Android自定义滑动验证条的示例代码,分享给大家,具体如下:*注:不知道为什么,h6的标签在这里没用了,所以我也只能用Markdown的语法来写了项目地址:https://github.com/994866755/handso...
    99+
    2023-05-30
    android 滑动验证条 roi
  • Android编程中自定义组件的示例分析
    这篇文章主要介绍了Android编程中自定义组件的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Android是什么Android是一种基于Linux内核的自由及开放...
    99+
    2023-05-31
    android
  • Android如何自定义带动画的半圆环型进度效果
    小编给大家分享一下Android如何自定义带动画的半圆环型进度效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!具体内容如下package com.ne...
    99+
    2023-05-31
    android
  • Android自定义view Path 的高级用法之搜索按钮动画
    关于Path之前写的也很多了,例如path绘制线,path绘制一阶,二阶和三阶贝塞尔路径,这些都是path的基本用法。今天我要带大家看的是Path 的高级用法,先上图,再吹。效果大致是这样的。看着是不是挺好。话不多说,切入正题:既然今天要谈...
    99+
    2023-05-31
    android view path
  • Java的自动装箱和拆箱源码分析
    这篇“Java的自动装箱和拆箱源码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java的自动装箱和拆箱源码分析”文章吧...
    99+
    2023-06-30
  • Android自定义仿ios加载弹窗的示例分析
    小编给大家分享一下Android自定义仿ios加载弹窗的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体内容如下效果如下:IosLoadDialog类(可直接复制):public class ...
    99+
    2023-06-15
  • Android自定义videoview仿抖音界面的示例分析
    这篇文章主要介绍Android自定义videoview仿抖音界面的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Android是什么Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用...
    99+
    2023-06-15
  • android中自定义View之复合控件的示例分析
    这篇文章给大家分享的是有关android中自定义View之复合控件的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。复合控件可以很好地创建出具有重用功能的控件集合。很多的APP都有一些共通的UI界面,为了统...
    99+
    2023-06-15
  • Angular.js数据绑定时自动转义html标签及内容的示例分析
    这篇文章主要介绍Angular.js数据绑定时自动转义html标签及内容的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!angularJS在进行数据绑定时默认是以字符串的形式...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作