RecyclerView——LayoutAnimation

之前看到系统中每个项目中都定义了N多的XML动画属性,不过我不准备去说动画,因为我之前使用RecyclerView的Item加了一些动画,所以来回顾一下相关的知识点

先看一下可能会用到的属性
attributesexplain
android:interpolator <set>可以用于动画的差值器,可以使用默认的差值器,该值必须是对指定插值器的资源的引用如:android:interpolator="@android:anim/decelerate_interpolator"
android:shareInterpolator <set>在使用set标签的时候,如果这个属性等于true那么就是说明你想在所有子元素中共享set标签下的这个插值器
android:ordering <set>指定此集合中动画的播放顺序。Value:sequentially(按顺序播放这组动画)Value:together (default)(同时播放集合中的动画)
android:fromAlpha<alpha>value为float,起始透明度偏移量,0为透明,1.0为不透明
android:toAlpha<alpha>value为float,结束透明度偏移量,0为透明,1.0为不透明
android:fromXScale <scale>value为float,起始的X方向上相对自身的缩放比例,1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍
android:toXScale <scale>value为float, 结束的X方向上相对自身的缩放比例,1.0代表自身无变化
android:fromYScale <scale>value为float,起始的Y方向上相对自身的缩放比例,1.0代表自身无变化
android:toYScale <scale>value为float, 结束的Y方向上相对自身的缩放比例 ,1.0代表自身无变化
android:pivotX <scale>变化时,起点X轴坐标不变,例如:设置为50%就是X方向坐标上的中点位置,可以是数值、百分数、百分数p
android:pivotY <scale>变化时,起点Y轴坐标不变,例如:设置为50%就是Y方向坐标上的中点位置,可以是数值、百分数、百分数p
android:fromXDelta <translate>起始点X轴坐标,可以是数值、百分数、百分数p
android:toXDelta <translate>结束点X轴坐标,可以是数值、百分数、百分数p
android:fromYDelta <translate>起始点Y轴坐标,可以是数值、百分数、百分数p
android:toYDelta <translate>结束点Y轴坐标,可以是数值、百分数、百分数p
android:fromDegrees <rotate>起始旋转的角度位置,度数为正代表顺时针方向,度数为负值表示逆时针方向
android:toDegrees <rotate>结束旋转的角度位置,度数为正代表顺时针方向,度数为负值表示逆时针方向
android:pivotX <rotate>旋转中心的X坐标,可以是数值、百分数、百分数p
android:pivotY <rotate>旋转中心的Y坐标,可以是数值、百分数、百分数p
android:propertyName <objectAnimator>必须设置为String 如:android:propertyName="string"
android:valueTo <objectAnimator>动画属性结束的值,必须设置为float, int, or color
android:valueFrom <objectAnimator>动画属性开始的值必须设置为float, int, or color
android:duration <objectAnimator>动画执行的时间,默认是300毫秒
android:startOffset <objectAnimator>int值 在start()之后,动画延迟的毫秒数
android:repeatCount <objectAnimator>多少次,重复一个动画。设置为 -1表示无限重复;设置为1 表示动画在初始运行后再重复一次,因此动画总共播放两次;默认值为0 ,表示动画不重复
android:repeatMode <objectAnimator>这个属性要想生效,那么android:repeatCount这个值为-1或者为正整数,可以设置两个值,reverse(从结束的位置继续),repeat (从新开始)
android:valueType<objectAnimator>首先是不需要指定颜色的属性,安卓的框架自己会处理,intType指定动画值是整数。floatType (默认)指定动画值是浮点数

关于数值、百分数、百分数p的用法。例如:value=20 当前View左上角(X,Y)处,增加20,然后以此为起始点变换;value=20%表示在当前View左上角(X,Y)+自己宽/高的20%做为起始点,然后以此为起始点变换;value=20%p P指的是parent,在当前的左上角(X,Y)加上父控件宽度的20%做为起始点X/Y轴坐标,然后以此为起始点变换。

上面列出了我们在XML常用到的各种动画属性标签的含义,这样就可以进入正题了。

为RecyclerView添加初始动画(LinearLayoutManager)

添加这个动画,我们可以写代码,可以继承ItemAnimator。既然上面介绍了那么多XML属性,那么就添加一个LayoutAnimation来实现吧。

LayoutAnimation是对于某一组控件的操作,就需要一个基本的动画来定义单个控件的动画,而且还可以定义动画的显示顺序和延迟时间。LayoutAnimation可以用在任何ViewGroup上

1.创建动画集合anim/item_animation_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_mediumAnimTime">

    <translate
        android:fromYDelta="-50%"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:toYDelta="0" />

    <alpha
        android:fromAlpha="0"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:toAlpha="1" />
    <scale
        android:fromXScale="125%"
        android:fromYScale="125%"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="100%"
        android:toYScale="100%" />

</set>

2.创建LayoutAnimation anim/layout_animation_down.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_animation_down"
    android:delay="20%"
    android:animationOrder="normal"/>

android:delay=”20%”
为每个item动画添加一个延时,0%将导致所有item同步运行,100%则让前一个item的动画运行完了下一个item才开始动画。我这里使用的是20%,表示item A的动画运行了20%之后再开始运行B的动画

3.应用LayoutAnimation,可以在代码中也可以在XML中

recyclerView.setLayoutManager(linearLayoutManager);
        LayoutAnimationController animation = AnimationUtils.
                loadLayoutAnimation(this, R.anim.layout_animation_down);
        recyclerView.setLayoutAnimation(animation);

或者

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"                                        
    android:layoutAnimation="@anim/layout_animation_down"/>

效果如下:
这里写图片描述

这里的RecyclerView和NestedScrollView一起用时,会感觉划不动,需要禁止NestedScrollView的滑动,调用一个方法即可解决冲突recyclerView.setNestedScrollingEnabled(false);

4.从底部,从左侧,从右侧进入的动画基本是一样的。改变 translate 的方向就可以了,依次是

<translate
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromYDelta="40%p"
        android:toYDelta="0"/>
 <translate
        android:interpolator="@android:anim/decelerate_interpolator"
        android:fromXDelta="-50%p"
        android:toXDelta="0"/>
 <translate
        android:interpolator="@android:anim/decelerate_interpolator"
        android:fromXDelta="50%p"
        android:toXDelta="0"/>

如果加载数据的时候,需要Item的动画重新展示一遍可以调用
recyclerView.scheduleLayoutAnimation();

为RecyclerView添加动画(GridLayoutManager)

如果是GridLayout添加动画,那么可能比上面稍微复杂一些

  • 先定义anim/grid_layout_animation.xml
<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_animation_down"
    android:animationOrder="normal"
    android:columnDelay="20%"
    android:directionPriority="column"
    android:direction="top_to_bottom|left_to_right"
    android:rowDelay="20%" />
  • android:animationOrder :控制动画内容的顺序
    可以设置三个值,分别是normal(引用的@anim里面怎么定义,那么动画顺序它就怎么执行) reverse (与normal执行方向相反)以及 random(随机的顺序)
  • android:directionPriority:加载动画设置方向优先级column(列优先)row(行优先)none(默认)
  • android:columnDelay:每列上的动画延迟
  • android:rowDelay:每行上的动画延迟
  • android:direction=”top_to_bottom|left_to_right” 动画执行的方向,动画将从左上角开始,移动到右下角
    如果定义为top_to_bottom|right_to_left,那么将从右上角开始移动到左下角。

  • 和上面一样,在代码中设置

GridLayoutAnimationController animation = (GridLayoutAnimationController) AnimationUtils.
                loadLayoutAnimation(this, R.anim.grid_layout_animation);
        recyclerView.setLayoutAnimation(animation);

那么会报错,因为LayoutAnimationController中只能识别LayoutAnimation,要想解决此问题。要重写RecyclerView,网上已经有人给出了解决办法。
我这里贴一下代码。

public class GridRecyclerView extends RecyclerView {
    /** @see View#View(Context) */
    public GridRecyclerView(Context context) { super(context); }

    /** @see View#View(Context, AttributeSet) */
    public GridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); }

    /** @see View#View(Context, AttributeSet, int) */
    public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }

    @Override
    protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params,
                                                   int index, int count) {
        final LayoutManager layoutManager = getLayoutManager();
        if (getAdapter() != null && layoutManager instanceof GridLayoutManager){

            GridLayoutAnimationController.AnimationParameters animationParams =
                    (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;

            if (animationParams == null) {
                // If there are no animation parameters, create new once and attach them to
                // the LayoutParams.
                animationParams = new GridLayoutAnimationController.AnimationParameters();
                params.layoutAnimationParameters = animationParams;
            }

            // Next we are updating the parameters

            // Set the number of items in the RecyclerView and the index of this item
            animationParams.count = count;
            animationParams.index = index;

            // Calculate the number of columns and rows in the grid
            final int columns = ((GridLayoutManager) layoutManager).getSpanCount();
            animationParams.columnsCount = columns;
            animationParams.rowsCount = count / columns;

            // Calculate the column/row position in the grid
            final int invertedIndex = count - 1 - index;
            animationParams.column = columns - 1 - (invertedIndex % columns);
            animationParams.row = animationParams.rowsCount - 1 - invertedIndex / columns;

        } else {
            // Proceed as normal if using another type of LayoutManager
            super.attachLayoutAnimationParameters(child, params, index, count);
        }
    }
}

这是因为RecyclerView是使用LayoutManager来布局自己的子view的,它并不知道LayoutManager如何放置子view。因此RecyclerView不知道到底该把AnimationParameter应用到list上还是grid上,而默认是list。为了修复这个问题我们需要一个自定义的RecyclerView,让它知道GridLayoutManager的存在。

那么效果图如下:

这里写图片描述


文章部分内容参考了:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0819/8397.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值