当前位置:Gxlcms > html代码 > Android动画三部曲之一ViewAnimation&LayoutAnimation_html/css_WEB-ITnose

Android动画三部曲之一ViewAnimation&LayoutAnimation_html/css_WEB-ITnose

时间:2021-07-01 10:21:17 帮助过:10人阅读

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

  • Tween动画
  • XML语法介绍
  • 插值器 Interpolator
  • 自定义Interpolator
  • 公共XML属性及对应的方法
  • ScaleAnimation 缩放动画
  • xml定义缩放动画
  • 代码定义缩放动画
  • RotateAnimation 旋转动画
  • xml中设置旋转动画
  • 代码中设置旋转动画
  • TranslateAnimation 平移动画
  • xml中设置平移动画
  • 代码中设置平移动画
  • AlphaAnimation 渐变动画
  • xml中设置渐变动画
  • 代码中设置渐变动画
  • AnimationSet 动画集合
  • xml中设置set动画集合
  • Frame动画
  • xml设置帧动画
  • 代码中设置帧动画
  • LayoutAnimationController
  • xml定义LayoutAnimation
  • 代码中定义LayoutAnimation
  • GridLayoutAnimationController
  • xml中定义
  • 代码中设置
  • RecyclerView扩展
  • Tween动画

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

    补间动画的基类是Animation。我们通常使用它的直接子类RotateAnimationTranslateAnimationScaleAnimationAlphaAnimation

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

    XML语法介绍

                                ...    

    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。可以简单的对系统的插值器进行一些参数值的修改:

    这里推荐大家一个第三方的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定义缩放动画

    然后通过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%]
  • 效果如下:

    RotateAnimation – 旋转动画

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

    效果图如下:

    TranslateAnimation – 平移动画

    XML属性名称 描述
    android:fromXDelta 平移动画起始位置X轴坐标
    android:toXDelta 平移动画结束位置X轴坐标
    android:fromYDelta 平移动画起始位置Y轴坐标
    android:toYDelta 平移动画结束位置Y轴坐标
    xml中设置平移动画:
    代码中设置平移动画
    TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 0);translateAnimation.setDuration(1000);translateAnimation.setInterpolator(new AnticipateOvershootInterpolator());targetIv.startAnimation(translateAnimation);

    AlphaAnimation – 渐变动画

    XML属性名称 描述
    android:fromAlpha 动画开始时操作对象的alpha值
    android:toAlpha 动画终止时操作对象的alpha值
    xml中设置渐变动画:
    代码中设置渐变动画:
    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);

    AnimationSet – 动画集合

    上面都是一个个的单独的动画,我们可以将很多个单独的动画组合到一起成为一个集合。

    动画集合也可以在xml中设置。需要用标签包括其他简单的动画。比上述公共动画属性多了一个android:shareInterpolator=”boolean”,表示是否对子动画设置相同的插值器。

    xml中设置set动画集合
                    


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

    再次修改之后,代码如下:

                    

    效果如下:

    Frame动画

    Frame动画就是把图片一帧一帧的播放出来的显示效果,类似于gif图片。帧动画设置很简单,只需要把每一帧对应的图片按照顺序添加进去,然后设置每一帧的显示时长,然后为view控件设置该动画,播放就行了。

    xml设置帧动画:
                                

    给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();

    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
            
    代码中定义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);

    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中定义
      
    代码中设置

    同样是使用一个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);

    效果如下:

    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.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

    人气教程排行