Android动画三部曲之中的一个 View Animation & LayoutAnimation

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/50612827

本篇文章对android的Tween动画帧动画以及布局动画进行总结。


Tween动画

Tween动画又称补间动画。通过对view的位置、大小、透明度、角度的改变来实现动画效果。

补间动画的基类是Animation。

我们通常使用它的直接子类RotateAnimationTranslateAnimationScaleAnimationAlphaAnimation

补间动画能够通过xml进行定义(res/anim/xxx),然后通过AnimationUtils类进行载入;也能够通过全然代码进行设置。


XML语法介绍

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation

Animation类定义了非常多常量和变量的初始值,比方:

public static final int INFINITE = -1;

public static final int RESTART = 1;

public static final int REVERSE = 2;

主要用到它的子类以及AnimationListener :

public static interface AnimationListener {
        /**
         * 动画開始的时候回调
         *
         * @param animation The started animation.
         */
        void onAnimationStart(Animation animation);
        /**
         * 动画结束的时候回调。

可是当设置动画反复次数为INFINITE的时候,该方法不会回调。 * * @param animation The animation which reached its end. */

void onAnimationEnd(Animation animation); /** * 动画反复播放的时候回调 * * @param animation The animation which was repeated. */ void onAnimationRepeat(Animation animation); }

加入此监听器能够对动画做很多其它的操作。


插值器 – Interpolator

介绍动画之前,得先说说”插值器”。

插值器的意思就是在播放动画的时候。改变播放的速率。能够使动画越来越快,或者越来越慢等。

经常使用的是一下九个插值器:

Baseinterpolator子类 Resource ID 描写叙述
AccelerateInterpolator @android:anim/accelerate_interpolator 加速变化(開始慢,越来越快)
DecelerateInterpolator @android:anim/decelerate_interpolator 减速变化(開始快,越来越慢)
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 先加速后减速(中间速度最快)
LinearInterpolator @android:anim/linear_interpolator 线性均匀变化
OvershootInterpolator @android:anim/overshoot_interpolator 超出结尾的临界值。然后在缓慢回到结束值
AnticipateInterpolator @android:anim/anticipate_interpolator 先向相反的方向改变一点,然后在加速播放
AnticipateOvershootInterpolator @android:anim/anitcipate_overshoot_interpolator 先向相反的方向改变一点,然后在加速播放至超出结束值一点,然后在缓慢回到结束值
BounceInterpolator @android:anim/bounce_interpolator 动画快结束的时候,模拟球落地的回弹效果
CycleInterpolator @android:anim/cycle_interpolator 动画循环播放指定的次数

自己定义Interpolator

一般来说,官方API给的这几个插值器就够有用了。只是还能够自己定义Interpolator。

能够简单的对系统的插值器进行一些參数值的改动:

<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
    android:attribute_name="value" />

这里推荐大家一个第三方的Interpolator库:

https://github.com/cimi-chen/EaseInterpolator


公共XML属性及相应的方法

属性名称 相应的方法 描写叙述
android:duration setDuration(long) 动画持续的时间长度(单位是miliseconds)
android:interpolator setInterpolator(Interpolator) 设置动画播放时的插值器
android:repeatCount setRepeatCount(int) 设置动画播放反复次数
android:repeatMode setRepeatMode(int) 设置动画反复的方式(当repeat count>0时才有效) “reverse“(2) or “restart“(1)
android:startOffset setStartOffset(long) 设置动画開始播放的延迟时间
android:fillAfter setFillAfter(boolean) 设置为true时。视图会停留在动画结束的状态。
android:fillBefore setFillBefore(boolean) 默认值是true,视图会停留在动画開始的状态
android:fillEnable setFillEnable(boolean) 默认值是false。假设是true,动画将会应用fillBefore值。否则,fillBefore的值会被忽略。transformation会在动画结束的时候被应用。
android:detachWallpaper setDetachWallpaper(boolean) 默认值是false。假设为true。而且动画窗口有一个壁纸的话,那么动画仅仅会应用给window,墙纸是静态不动的
android:zAdjustment setZAdjustment(int) 同意在动画播放期间,调整播放内容在Z轴方向的顺序。

top“(1) or “normal“(0) or “bottom“(-1)

android:zAdjustment:同意在动画播放期间,调整播放内容在Z轴方向的顺序:

  • normal(0):正在播放的动画内容保持当前的Z轴顺序,
  • top(1):在动画播放期间,强制把当前播放的内容放到其它内容的上面;
  • bottom(-1):在动画播放期间,强制把当前播放的内容放到其它内容之下

ScaleAnimation – 缩放动画

XML属性名称 描写叙述
android:fromXScale 动画起始时,X轴坐标的伸缩尺寸。0.0表示收缩到没有。1.0表示正常没伸缩。>1.0表示放大。<1.0表示收缩。
android:toXScale 动画结束时X轴坐标的伸缩尺寸
android:fromYScale 动画起始时Y轴坐标的伸缩尺寸
android:toYScale 动画结束时Y轴坐标的伸缩尺寸
android:pivotX 缩放动画作用点在X轴方向上的位置。

android:pivotX=”50”表示绝对定位,相对于零点偏移50 –> Animation.ABSOLUTE android:pivotX=”50%”表示相对控件本身 –> Animation.RELATE_TO_SELF android:pivotX=”50%p”表示相对控件的父控件 –> Animation.RELATE_TO_PARENT

android:pivotY 缩放动画作用点在Y轴方向上的位置
xml定义缩放动画
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@color/blue_light"
    android:duration="1000"
    android:fillAfter="false"
    android:fillBefore="true"
    android:fromXScale="1"
    android:fromYScale="1"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="1"
    android:repeatMode="restart"
    android:startOffset="500"
    android:toXScale="0"
    android:toYScale="0"
    android:zAdjustment="bottom" />

然后通过AnimationUtils类装载动画,进行应用。

Animation scaleAnimation =  AnimationUtils.loadAnimation(this, R.anim.scale_anim);
targetIv.startAnimation(scaleAnimation);
代码定义缩放动画
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.5f, 1.0f, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
scaleAnimation.setInterpolator(new OvershootInterpolator());
scaleAnimation.setFillAfter(true);
targetIv.startAnimation(scaleAnimation);

ScaleAnimation有4个构造方法。

public ScaleAnimation(Context context, AttributeSet attrs) {}
public ScaleAnimation(float fromX, float toX, float fromY, float toY) {}
public ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) {}
public ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {}

第一个构造用于从资源文件里载入资源。我们主要用后三个。后面三个构造的差别就在设置变换中轴点与否。

不指定pivotXType和pivotYType的话。默认採用ABSOLUTE形式,pivotX与pivotY的值都是相对于(0,0)左上角偏移的。

pivotXType可设置的參数有三种:ABSOLUTE、RELATE_TO_SELF、RELATE_TO_PARENT。

  • ABSOLUTE表示当前设置的pivotX和pivotY值是绝对值,相对于左上角偏移。

    比方:android:pibotX=”50”

  • RELATE_TO_SELF表示设置的pivotX和pivotY是相对值。比方:android:pivotX = “50%”表示X方向中轴点在正中间。 取值范围是[0% ~ 100%]
  • RELATE_TO_PARENT也是表示相对值。是相对于该视图的父控件而言。比方:android:pivotX = “50%p”表示X方向中轴点是其父控件的中间位置。取值范围是[0% ~ 100%]

效果例如以下:

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


RotateAnimation – 旋转动画

XML属性名称 描写叙述
android:fromDegrees 动画起始的角度(可正可负)
android:toDegrees 动画终止的角度(可正可负)
android:pivotX 旋转作用点在X轴方向上的位置。android:pivotX=”50”表示绝对定位,相对于零点偏移50 android:pivotX=”50%”表示相对控件本身 android:pivotX=”50%p”表示相对控件的父控件
android:pivotY 旋转作用点在Y轴方向上的位置
xml中设置旋转动画
<?

xml version="1.0" encoding="utf-8"?>

<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2500" android:fillAfter="true" android:fromDegrees="-20" android:interpolator="@android:anim/overshoot_interpolator" android:pivotX="50%" android:pivotY="50%" android:toDegrees="320" />
代码中设置旋转动画
RotateAnimation rotateAnimation = new RotateAnimation(0.0f, 550.0f, Animation.RELATIVE_TO_SELF, 0.3f, Animation.RELATIVE_TO_SELF, 0.3f);
rotateAnimation.setDuration(1500);
rotateAnimation.setInterpolator(new OvershootInterpolator());
rotateAnimation.setFillAfter(true);
targetIv.startAnimation(rotateAnimation);

效果图例如以下:

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


TranslateAnimation – 平移动画

XML属性名称 描写叙述
android:fromXDelta 平移动画起始位置X轴坐标
android:toXDelta 平移动画结束位置X轴坐标
android:fromYDelta 平移动画起始位置Y轴坐标
android:toYDelta 平移动画结束位置Y轴坐标
xml中设置平移动画:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:interpolator="@android:anim/anticipate_overshoot_interpolator"
    android:toXDelta="50%p"
    android:toYDelta="50%p" />
代码中设置平移动画
TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 0);
translateAnimation.setDuration(1000);
translateAnimation.setInterpolator(new AnticipateOvershootInterpolator());
targetIv.startAnimation(translateAnimation);

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


AlphaAnimation – 渐变动画

XML属性名称 描写叙述
android:fromAlpha 动画開始时操作对象的alpha值
android:toAlpha 动画终止时操作对象的alpha值
xml中设置渐变动画:
<?

xml version="1.0" encoding="utf-8"?>

<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromAlpha="1.0" android:interpolator="@android:anim/linear_interpolator" android:repeatCount="1" android:repeatMode="reverse" android:toAlpha="0.0" />
代码中设置渐变动画:
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.2f);
alphaAnimation.setDuration(1500);
alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
alphaAnimation.setRepeatMode(Animation.REVERSE);
alphaAnimation.setRepeatCount(1);
targetIv.startAnimation(alphaAnimation);

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


AnimationSet – 动画集合

上面都是一个个的单独的动画,我们能够将非常多个单独的动画组合到一起成为一个集合。

动画集合也能够在xml中设置。须要用标签包含其它简单的动画。

比上述公共动画属性多了一个android:shareInterpolator=”boolean”,表示是否对子动画设置相同的插值器。

xml中设置set动画集合
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:shareInterpolator="false">
    <alpha
        android:duration="1500"
        android:fillAfter="true"
        android:fromAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0.2" />
    <scale
        android:duration="1000"
        android:fromXScale="0.8"
        android:fromYScale="0.8"
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="60%"
        android:pivotY="20%"
        android:startOffset="1500"
        android:toXScale="0.3"
        android:toYScale="0.5" />
    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:interpolator="@android:anim/bounce_interpolator"
        android:startOffset="2500"
        android:toXDelta="200"
        android:toYDelta="200" />
    <rotate
        android:duration="1000"
        android:fromDegrees="50"
        android:interpolator="@android:anim/anticipate_overshoot_interpolator"
        android:pivotX="50%p"
        android:pivotY="50%p"
        android:startOffset="3500"
        android:toDegrees="360" />
</set>


我们来看一个现象:
设置了上面的set动画之后。開始执行的时候,会发现渐变动画開始执行的时候,会先变小。旋转一个角度。然后才開始动画。细致分析xml代码之后,发现是在动画開始的时候,把scale和rotate中的初始状态给应用了。这时候想起了android:fillBefore属性。
然后在scale、rotate 动画里加入了android:fillBefore=”false”属性之后。发现还是不好使。查看Animation类的源代码发现。fillBefore必须在设置fillEnable=”true”的时候才神效。而且fillBefore的默认值是true,所以才会出现上述情况。

再次改动之后。代码例如以下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:shareInterpolator="false">
    <alpha
        android:duration="1500"
        android:fillAfter="true"
        android:fromAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0.2" />
    <scale
        android:duration="1000"
        android:fillBefore="false"
        android:fillEnabled="true"
        android:fromXScale="0.8"
        android:fromYScale="0.8"
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="60%"
        android:pivotY="20%"
        android:startOffset="1500"
        android:toXScale="0.3"
        android:toYScale="0.5" />
    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:interpolator="@android:anim/bounce_interpolator"
        android:startOffset="2500"
        android:toXDelta="200"
        android:toYDelta="200" />
    <rotate
        android:duration="1000"
        android:fillBefore="false"
        android:fillEnabled="true"
        android:fromDegrees="50"
        android:interpolator="@android:anim/anticipate_overshoot_interpolator"
        android:pivotX="50%p"
        android:pivotY="50%p"
        android:startOffset="3500"
        android:toDegrees="360" />
</set>

效果例如以下:

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


Frame动画

Frame动画就是把图片一帧一帧的播放出来的显示效果,相似于gif图片。帧动画设置非常easy。仅仅须要把每一帧相应的图片依照顺序加入进去,然后设置每一帧的显示时长,然后为view控件设置该动画,播放即可了。

xml设置帧动画:
<?

xml version="1.0" encoding="utf-8"?>

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/person1" android:duration="100" /> <item android:drawable="@drawable/person2" android:duration="100" /> <item android:drawable="@drawable/person3" android:duration="100" /> <ite android:drawable="@drawable/person4" android:duration="100" /> <item android:drawable="@drawable/person5" android:duration="100" /> <item android:drawable="@drawable/person6" android:duration="100" /> <item android:drawable="@drawable/person7" android:duration="100" /> </animation-list>

给ImageView设置动画:

targetIv.setBackgroundResource(R.drawable.frame_anim);
AnimationDrawable animationDrawable = (AnimationDrawable) targetIv.getBackground();
animationDrawable.start();
代码中设置帧动画
AnimationDrawable animationDrawable = new AnimationDrawable();
animationDrawable.setOneShot(false);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person1), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person2), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person3), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person4), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person5), 200);
targetIv.setImageDrawable(animationDrawable);
animationDrawable.start();

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


LayoutAnimationController

Tween Animation和Frame Animation都是针对单个view操作的。而LayoutAnimationController能够针对一个ViewGroup进行动画操作,能够让一组view的每一个view依照一定的规则展示动画。
比方:能够针对listView、gridView或者recyclerView,定义item的出场动画,而不是非常死板的一下子全显示出来。

一般对ListView使用layoutAnimation动画,对GridView使用gridLayoutAnimation动画。

对RecyclerView来说。正常情况下仅仅能使用layoutAnimation动画。应用gridLayoutAnimation动画的时候会报错。不错能够针对RecyclerView生成一个子类做一下处理进行支持gridLayoutAnimation动画。

xml属性 相应的方法 描写叙述
android:delay setDelay(float) 动画播放的延迟时间
android:animationOrder setOrder(int) 子view播放动画的顺序 [ normal
android:interpolator setInterpolator(Interpolator) setIntepolator(Context, @InterpolatorRes int) 插值器
android:animation LayoutAnimationController(animation) 指定子view的动画
xml定义LayoutAnimation
<?xml version="1.0" encoding="utf-8"?

>

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

>

<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:shareInterpolator="true"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" /> <translate android:fromXDelta="-100%" android:toXDelta="0%" /> </set>
代码中定义LayoutAnimation
public LayoutAnimationController(Animation animation) {
    this(animation, 0.5f);
}
public LayoutAnimationController(Animation animation, float delay) {
    mDelay = delay;
    setAnimation(animation);
}

LayoutAnimationController有三个构造函数,经常使用的时候上面两个。

delay表示每一个子view启动动画的延迟时间,默认是0.5f。delay以秒为单位

Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_list_anim);
        LayoutAnimationController layoutAnimationController = new LayoutAnimationController(animation);
        layoutAnimationController.setInterpolator(new AccelerateInterpolator());
        layoutAnimationController.setDelay(0.5f);
        layoutAnimationController.setOrder(LayoutAnimationController.ORDER_RANDOM);
        recyclerView.setLayoutAnimation(layoutAnimationController);

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


GridLayoutAnimationController

GridLayoutAnimationController是LayoutAnimationController的子类。针对GridView做动画操作。

xml属性 相应的方法 描写叙述
android:delay setDelay(float) 动画播放的延迟时间
android:columnDelay setColumnDelay(float) 列播放动画的延迟时间
android:rowDelay setRowDelay(float) 行播放动画的延迟时间
android:animationOrder setOrder(int) 子view播放动画的顺序 [ normal
android:animation LayoutAnimationController(animation) 指定子view的动画
xml中定义
  <GridView
        android:id="@+id/test_grid_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnWidth="60dp"
        android:gravity="center"
        android:horizontalSpacing="10dp"
        android:layoutAnimation="@anim/grid_layout_anim"
        android:numColumns="3"
        android:padding="10dp"
        android:scrollbars="none"
        android:stretchMode="columnWidth"
        android:verticalSpacing="10dp" />
<?xml version="1.0" encoding="utf-8"?>
<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_anim_alpha"
    android:columnDelay="0.5"
    android:direction="bottom_to_top|right_to_left"
    android:directionPriority="row" />
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromAlpha="0.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="1.0" />
代码中设置

相同是使用一个Animation构造出GridLayoutAnimation对象。然后设置各种參数,最后设置此动画GridView即可。

Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_anim_alpha);
GridLayoutAnimationController gridLayoutAnimationController = new GridLayoutAnimationController(animation);
gridLayoutAnimationController.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP | GridLayoutAnimationController.DIRECTION_RIGHT_TO_LEFT);
gridLayoutAnimationController.setDirectionPriority(GridLayoutAnimationController.PRIORITY_ROW);
gridRecyclerView.setLayoutAnimation(gridLayoutAnimationController);

效果例如以下:

Android动画三部曲之中的一个 View Animation &amp; LayoutAnimation


RecyclerView扩展

正常情况下,我们能够对RecyclerView使用LayoutAnimation动画。可是假设对RecycleView使用动画的时候出现下面错误:

AndroidRuntime: FATAL EXCEPTION: main                                                       
Process: com.jacksen.demo.view, PID: 30770                                                  
java.lang.ClassCastException: android.view.animation.LayoutAnimationController$AnimationParameters cannot be cast to android.view.animation.GridLayoutAnimationController$AnimationParameters
                   at android.view.animation.GridLayoutAnimationController.getDelayForView(GridLayoutAnimationController.java:299)
                   at android.view.animation.LayoutAnimationController.getAnimationForView(LayoutAnimationController.java:321)
                   at android.view.ViewGroup.bindLayoutAnimation(ViewGroup.java:3717)
                   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2892)
                   ......

意思就是GridLayoutAnimationController.AnimationParameters不能强转成LayoutAnimationController.AnimationParameters。

RecyclerView的出现本来就是替代Listview的,可是它有能够展示出GridView的效果,可是怎么让RecyclerView设置GridLayoutManager的时候应用gridLayoutAnimation动画呢?

我们先来看看Gridview怎么实现的?

在GridView源代码里面搜索”LayoutAnimation”关键字发现,仅仅有一个attachLayoutAnimationParameters()的函数。里面将layoutAnimationParameters强转成GridLayoutAnimationController.AnimationParameters。

@Override
    protected void attachLayoutAnimationParameters(View child,
            ViewGroup.LayoutParams params, int index, int count) {
        GridLayoutAnimationController.AnimationParameters animationParams =
                (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;
        if (animationParams == null) {
            animationParams = new GridLayoutAnimationController.AnimationParameters();
            params.layoutAnimationParameters = animationParams;
        }
        animationParams.count = count;
        animationParams.index = index;
        animationParams.columnsCount = mNumColumns;
        animationParams.rowsCount = count / mNumColumns;
        if (!mStackFromBottom) {
            animationParams.column = index % mNumColumns;
            animationParams.row = index / mNumColumns;
        } else {
            final int invertedIndex = count - 1 - index;
            animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns);
            animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns;
        }
    }

然后就想到去RecyclerView中去找attachLayoutAnimationParameters()方法,可是没有。其父类ViewGroup里面有此方法:

protected void attachLayoutAnimationParameters(View child,
            LayoutParams params, int index, int count) {
        LayoutAnimationController.AnimationParameters animationParams =
                    params.layoutAnimationParameters;
        if (animationParams == null) {
            animationParams = new LayoutAnimationController.AnimationParameters();
            params.layoutAnimationParameters = animationParams;
        }
        animationParams.count = count;
        animationParams.index = index;
    }

由此可见RecyclerView默认实现了ViewGroup的LayoutAnimation。我们在RecyclerView中将此方法重写一下。只是要将mStackFromButtom參数的推断去掉

public class GridRecyclerView extends RecyclerView {
    public GridRecyclerView(Context context) {
        super(context);
    }
    public GridRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);
    }
    @Override
    public void setLayoutManager(LayoutManager layout) {
        if (layout instanceof GridLayoutManager) {
            super.setLayoutManager(layout);
        } else {
            throw new ClassCastException("you should only use the GridLayoutManager as LayoutManager when you use this " + this.getClass().getSimpleName() + " class");
        }
    }
    @Override
    protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) {
        if (getLayoutManager() != null && getLayoutManager() instanceof GridLayoutManager) {
            GridLayoutAnimationController.AnimationParameters animationParams =
                    (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;
            if (animationParams == null) {
                animationParams = new GridLayoutAnimationController.AnimationParameters();
                params.layoutAnimationParameters = animationParams;
            }
            int mNumColumns = ((GridLayoutManager) getLayoutManager()).getSpanCount();
            animationParams.count = count;
            animationParams.index = index;
            animationParams.columnsCount = mNumColumns;
            animationParams.rowsCount = count / mNumColumns;
            final int invertedIndex = count - 1 - index;
            animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns);
            animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns;
        } else {
            super.attachLayoutAnimationParameters(child, params, index, count);
        }
    }
}

当我们使用GridLayoutManager的时候,不能使用此属性。

/**
     * stackFromEnd is not supported by GridLayoutManager. Consider using
     * {@link #setReverseLayout(boolean)}.
     */
    @Override
    public void setStackFromEnd(boolean stackFromEnd) {
        if (stackFromEnd) {
            throw new UnsupportedOperationException(
                    "GridLayoutManager does not support stack from end."
                            + " Consider using reverse layout");
        }
        super.setStackFromEnd(false);
    }

此篇blog到此结束~
感谢大家支持!如有错误。请指出~
谢谢~


參考:

http://developer.android.com/intl/zh-cn/guide/topics/graphics/view-animation.html
http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0619/3090.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0915/3462.html?

utm_source=tuicool&utm_medium=referral