使用LayoutAnimationController为RecyclerView添加动画

@author:莫川

一、前言

为RecyclerView的Item添加动画有很多中方案,比如通过设置setItemAnimator来实现或者是通过遍历RecyclerView中的子View,然后分别对子View做动画。今天介绍一种更加简单的方式:通过LayoutAnimationController的方式,对RecyclerView的Item做动画。

二、效果以及源码

先看效果:首先是对LinearLayoutManager的RecyclerView。

  • 1.使用LayoutAnimationController的8种动画的播放效果

  • 2.使用GridLayoutAnimationController的8种动画的播放效果

Github源码:https://github.com/nuptboyzhb/RecyclerViewAnimation

三、实现方案

(1)LayoutAnimationController

比如实现从依次从左侧进入的动画效果,我们首先需要实现一个Item的动画效果,然后创建一个LayoutAnimationController对象,并设置每一个item播放动画的时间延时和item的播放顺序。

以从左侧进入为例,每个单独的Item的动画如下:

  • 1.Item动画
.../*** 从左侧进入,并带有弹性的动画** @return*/public static AnimationSet getAnimationSetFromLeft() {AnimationSet animationSet = new AnimationSet(true);TranslateAnimation translateX1 = new TranslateAnimation(RELATIVE_TO_SELF, -1.0f, RELATIVE_TO_SELF, 0.1f,RELATIVE_TO_SELF, 0, RELATIVE_TO_SELF, 0);translateX1.setDuration(300);translateX1.setInterpolator(new DecelerateInterpolator());translateX1.setStartOffset(0);TranslateAnimation translateX2 = new TranslateAnimation(RELATIVE_TO_SELF, 0.1f, RELATIVE_TO_SELF, -0.1f,RELATIVE_TO_SELF, 0, RELATIVE_TO_SELF, 0);translateX2.setStartOffset(300);translateX2.setInterpolator(new DecelerateInterpolator());translateX2.setDuration(50);TranslateAnimation translateX3 = new TranslateAnimation(RELATIVE_TO_SELF, -0.1f, RELATIVE_TO_SELF, 0f,RELATIVE_TO_SELF, 0, RELATIVE_TO_SELF, 0);translateX3.setStartOffset(350);translateX3.setInterpolator(new DecelerateInterpolator());translateX3.setDuration(50);animationSet.addAnimation(translateX1);animationSet.addAnimation(translateX2);animationSet.addAnimation(translateX3);animationSet.setDuration(400);return animationSet;}...

为了让Item看起来有‘弹性’效果,animationSet添加了三个移动动画,分别是从左侧进入(-100%),移动到右侧的10%,然后在从右侧(10%)移动到左侧(-10%),最后再从(-10%)移动到原本的位置(0%)。这样就有了移动后的弹性效果。

  • 2.设置LayoutAnimationController的属性

2.1 设置ViewGroup的子View播放动画之间的offset。

/*** Sets the delay, as a fraction of the animation duration, by which the children's animations are offset.*/
void setDelay(float delay)

2.2 设置ViewGroup的子View播放动画的顺序

/*** Sets the order used to compute the delay of each child's animation.*/
void setOrder(int order)

setOrder可以取值为LayoutAnimationController.ORDER_NORMAL(正常顺序),LayoutAnimationController.ORDER_RANDOM(随机顺序)以及LayoutAnimationController.ORDER_REVERSE(逆序)。这里的demo设置的是正常顺序。

  • 3.播放动画
   /*** 播放RecyclerView动画** @param animation* @param isReverse*/public void playLayoutAnimation(Animation animation, boolean isReverse) {LayoutAnimationController controller = new LayoutAnimationController(animation);controller.setDelay(0.1f);controller.setOrder(isReverse ? LayoutAnimationController.ORDER_REVERSE : LayoutAnimationController.ORDER_NORMAL);mRecyclerView.setLayoutAnimation(controller);mRecyclerView.getAdapter().notifyDataSetChanged();mRecyclerView.scheduleLayoutAnimation();}

通过viewGroup.setLayoutAnimation设置layout动画。然后通知ViewGroup重新绘制,调用scheduleLayoutAnimation方法播放动画。

(2)GridLayoutAnimationController

上述方法针对的是线性的RecyclerView,也就是说RecyclerView的LayoutManager设置的是LinearLayoutManager.

    ...@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main_list);Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);mRecyclerView.setLayoutManager(new LinearLayoutManager(this));mRecyclerView.setAdapter(new DemoRecyclerViewAdapter());}...

而对于使用GridLayoutManager和StaggeredGridLayoutManager的RecyclerView来说,我们需要使用GridLayoutAnimationController,其他步骤与LayoutAnimationController一致。

    ...@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main_grid);Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);mRecyclerView = (StaggeredGridRecyclerView) findViewById(R.id.recycler_view);mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));mStaggeredGridAdapter = new StaggeredGridAdapter();mStaggeredGridAdapter.setDataSet(mockData());mRecyclerView.setAdapter(mStaggeredGridAdapter);}....

同样的,仍然使用之前的Animation创建GridLayoutAnimationController。

   .../*** 播放动画** @param animation* @param isReverse*/public void playLayoutAnimation(Animation animation, boolean isReverse) {GridLayoutAnimationController controller = new GridLayoutAnimationController(animation);controller.setColumnDelay(0.2f);controller.setRowDelay(0.3f);controller.setOrder(isReverse ? LayoutAnimationController.ORDER_REVERSE : LayoutAnimationController.ORDER_NORMAL);mRecyclerView.setLayoutAnimation(controller);mRecyclerView.getAdapter().notifyDataSetChanged();mRecyclerView.scheduleLayoutAnimation();}...

GridLayoutAnimationController的delay方法可以分别按照Column和Row维度进行设置。

本以为到此顺利结束。运行后发现,会Crash,log为:

...
E/AndroidRuntime( 7876): java.lang.ClassCastException: android.view.animation.LayoutAnimationController$AnimationParameters cannot be cast to android.view.animation.GridLayoutAnimationController$AnimationParameters
E/AndroidRuntime( 7876):     at android.view.animation.GridLayoutAnimationController.getDelayForView(GridLayoutAnimationController.java:299)
E/AndroidRuntime( 7876):     at android.view.animation.LayoutAnimationController.getAnimationForView(LayoutAnimationController.java:321)
E/AndroidRuntime( 7876):     at android.view.ViewGroup.bindLayoutAnimation(ViewGroup.java:4227)
E/AndroidRuntime( 7876):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3272)
E/AndroidRuntime( 7876):     at android.view.View.draw(View.java:15618)
E/AndroidRuntime( 7876):     at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3869)
E/AndroidRuntime( 7876):     at android.view.View.updateDisplayListIfDirty(View.java:14495)
E/AndroidRuntime( 7876):     at android.view.View.getDisplayList(View.java:14524)
E/AndroidRuntime( 7876):     at android.view.View.draw(View.java:15315)
E/AndroidRuntime( 7876):     at android.view.ViewGroup.drawChild(ViewGroup.java:3536)
E/AndroidRuntime( 7876):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3329)
E/AndroidRuntime( 7876):     at android.view.View.draw(View.java:15618)
E/AndroidRuntime( 7876):     at android.view.View.updateDisplayListIfDirty(View.java:14495)
E/AndroidRuntime( 7876):     at android.view.View.getDisplayList(View.java:14524)
...

为了解决这个问题,我们需要override RecyclerView的attachLayoutAnimationParameters方法:

package com.github.nuptboyzhb.recyclerviewanimation.grid;import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.GridLayoutAnimationController;/*** @version Created by haibozheng on 2016/12/9.* @Author Zheng Haibo* @Blog github.com/nuptboyzhb* @Company Alibaba Group* @Description StaggeredGridRecyclerView*/
public class StaggeredGridRecyclerView extends RecyclerView {public StaggeredGridRecyclerView(Context context) {super(context);}public StaggeredGridRecyclerView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public StaggeredGridRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}/*** 支持GridLayoutManager以及StaggeredGridLayoutManager** @param child* @param params* @param index* @param count*/@Overrideprotected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params,int index, int count) {LayoutManager layoutManager = this.getLayoutManager();if (getAdapter() != null && (layoutManager instanceof GridLayoutManager|| layoutManager instanceof StaggeredGridLayoutManager)) {GridLayoutAnimationController.AnimationParameters animationParams =(GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;if (animationParams == null) {animationParams = new GridLayoutAnimationController.AnimationParameters();params.layoutAnimationParameters = animationParams;}int columns = 0;if (layoutManager instanceof GridLayoutManager) {columns = ((GridLayoutManager) layoutManager).getSpanCount();} else {columns = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();}animationParams.count = count;animationParams.index = index;animationParams.columnsCount = columns;animationParams.rowsCount = count / columns;final int invertedIndex = count - 1 - index;animationParams.column = columns - 1 - (invertedIndex % columns);animationParams.row = animationParams.rowsCount - 1 - invertedIndex / columns;} else {super.attachLayoutAnimationParameters(child, params, index, count);}}
}

更多动画效果,请参见Github源码:https://github.com/nuptboyzhb/RecyclerViewAnimation

四、总结

通过LayoutAnimationController或者GridLayoutAnimationController来实现RecyclerView的动画,非常简单,而且效果很好。该方式不仅可以应用于RecyclerView,而且还适用于ListView、LinearLayout、GridView等ViewGroup。比如,如下是作用在一个LinearLayout的效果。

使用LayoutAnimationController为RecyclerView添加动画相关推荐

  1. Android添加item动画,RecyclerView基础篇-Item添加动画

    Android_Banner.jpg 简介 本节中我们介绍下给RecyclerView中的Item添加动画. 添加的动画,分为,在打开列表时有Item的展示动画,当滑动的时候没有动画 和打开列表滑动时 ...

  2. recyclerview item动画_这可能是你见过的迄今为止最简单的RecyclerView Item加载动画...

    如何实现RecyclerView Item动画? 这个问题想必有很多人都会讲,我可以用ItemAnimator实现啊,这是RecyclerView官方定义的接口,专门扩展Item动画的,那我为什么要寻 ...

  3. AndroidUI 布局动画-为布局添加动画

    除了可以为视图添加动画以外,还可以为视图的布局添加动画: <RelativeLayout xmlns:android="http://schemas.android.com/apk/r ...

  4. Android RecyclerView布局动画

    In this tutorial, we'll be discussing and implementing RecyclerView Layout Animations in our Android ...

  5. 面试官:RecyclerView布局动画原理了解吗?

    前言 温馨提示:文章有点长,建议关注微信公众号"字节小站"收藏阅读 本文主要通过以下几个方面来讲解RecyclerView的布局和动画原理: 布局放置:RecyclerView#d ...

  6. Android RecyclerView添加Header头部

     Android RecyclerView添加Header头部 Android RecyclerView不像以前的ListView那样直接添加头部,如果要给RecyclerView增加头部,则需要 ...

  7. 给网页图标字体 Font Awesome 添加动画效果

    在国外网站中使用Web字体已经流行起来,虽然使用中文不太靠谱,但我们可以使用图标字体,也是很是方便的,图标字体有很多,可看<30个免费网页图标字体以及使用方法>一文,其中Font Awes ...

  8. Android移动开发之【Android实战项目】Recyclerview添加花色分割线

    最近在做项目的过程中发现干巴巴的Recyclerview真的不好看,这里讲一下怎么一句话加默认的分割线,并且改变分割线的样式. 文章目录 一.添加默认分割线 二.修改样式 三.设置方法 通过 setD ...

  9. android图片跳转动画效果,Android实现Activity界面切换添加动画特效的方法

    本文以实例形式展示了Android实现Activity界面切换添加动画特效的方法,对于Android程序设计人员来说有很好的参考借鉴价值.具体方法如下: 了解Android程序设计的人应该知道,在An ...

最新文章

  1. Spring Boot 为什么这么火?
  2. runc容器逃逸漏洞最强后续:应对之策汇总与热点疑问解答
  3. Spark Run本地设计模式
  4. 如果从SVN到GIT
  5. (25)HTML5之<canvas>和<svg>标签
  6. java 展现层框架_spring快速入门例子教程:06展现层
  7. C语言的延时程序怎么改,C语言编程,怎么用按键来改变延时的长短?
  8. 硬核软件开发者 30 多年的 11 条经验教训
  9. Dell服务器中Lsiutil命令常见使用
  10. 利用c#反射提高设计灵活性
  11. Kotlin — 适用于服务器开发
  12. crunch 生成密码用例
  13. Podfile 文件模板
  14. LBS (基于位置服务)-- Location Based Service
  15. 最炫黑科技还得谷歌!一副眼镜告别学外语,一个地图App在家沉浸式环球游
  16. 调用支付宝第三方支付接口详解(沙箱环境)
  17. hutool 读取扩展名文件_好多公司都要用的一些知识点Office办公软件、文件加密、文件扩展名!...
  18. php redis超卖,PHP用redis解决超卖的问题
  19. 计算机考研数学考数学二的专业,考研常识:哪些专业考数学二?
  20. 爱心捐赠爱传情 暖心行动暖寒冬

热门文章

  1. 实现一个MVVM和promise
  2. Eclipse安装阿里巴巴Java开发规约插件
  3. 字符串转换成java对象然后通过@RestController返回json对象
  4. 乘法运算-快速傅里叶变换
  5. 三维重建4:Jacobian矩阵和Hessian矩阵
  6. mysqladmin 设置用户名初始密码报错you need the SUPER privilege for this operation
  7. 2017面试分享(js面试题记录)
  8. python系列(三)python列表详解
  9. ExtJs之Ext.view.View
  10. Spring框架的设计理念与设计模式分析