Android 动画

不怕跌倒,所以飞翔

Android动画分类

1.View动画

1.1 View动画有四种变换效果(对应这Animation的四个子类):

  • TranslateAnimation(平移动画)
  • ScaleAnimation(缩放动画)
  • RotateAnimation(旋转动画)
  • AlphaAnimation(透明度动画)

1.2 View动画的使用

  • 1.2.1 XML方式使用动画
  • 1.2.2代码方式使用动画

1.2.1 XML方式使用动画

这里首先要说明一下创建的位置(一定是在res下面创建anim文件夹) : res/anim/XXX.xml

1.2.1.1整体的属性
  • android:duration 动画执行时间
  • android:fillAfter 动画结束后View是否停留在结束为止
  • android:interpolator 插值器默认为(加速减速插值器)@animation:anim/accelerate_decelerate_interpolator
  • android:shareInterpolator 是否共享插值器
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
     android:shareInterpolator="true"/>

这个后面在仔细说....

1.2.1.2平移动画(对应TranslateAnimation类)
  • fromXDelta 表示x的起始值,比如0,0%p
  • fromYDelta 表示y的起始值,比如100,100%p
  • toXDelta 表示x的结束值
  • toYDelta 表示y的结束值
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="0"
        />
</set>
1.2.1.3缩放动画(对应ScaleAnimation类)
  • android:fromXScale x水平方向缩放起始值,比如:0
  • android:fromYScale y水平方向缩放起始值,比如:0
  • android:toXScale x竖直方向缩放起始值
  • android:toYScale y竖直方向缩放起始值
  • android:toXScale 缩放轴点的X坐标
  • android:toYScale 缩放轴点的Y坐标
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:fillAfter="false"
     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
     android:shareInterpolator="true">

    <scale
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="0.5"
        android:pivotY="0.5"
        android:toXScale="1"
        android:toYScale="1"
        />
</set>

这里解释一下上面那段代码,就是从没有(因为是从0开始)到正常大小(这里的正常大小指的是原始尺寸),中心点要是"%"的话是指相对于自身控件的百分比但是如果要是"0.5"的话不代表"50%"而是指的是实际的像素点

1.2.1.4 旋转动画(对应RotateAnimation类)
  • android:fromDegrees 旋转的开始角度
  • android:toDegrees 旋转的结束角度
  • android:pivotX 旋转的x轴点
  • android:pivotY 旋转的y轴点
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="5000"
     android:fillAfter="false"
     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
     android:shareInterpolator="true">

    <rotate
        android:fromDegrees="0"
        android:pivotX="0.5"
        android:pivotY="0.5"
        android:toDegrees="359"/>
</set>
1.2.1.5 透明度动画 (对应AlphaAnimation)
  • android:fromAlpha 透明度的起始值
  • android:toAlpha 透明度的结束值
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="5000"
     android:fillAfter="false"
     android:interpolator="@android:anim/accelerate_decelerate_interpolator"
     android:shareInterpolator="true">

    <alpha
        android:fromAlpha="0.5"
        android:toAlpha="1"/>
</set>
1.2.1.6使用的代码:
        Animation translateAnimation = AnimationUtils.loadAnimation(this,R.anim.translate_animation);
        mIvAnimation.startAnimation(translateAnimation);

1.2.2 代码使用

        AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
        alphaAnimation.setDuration(500);
        mIvAnimation.setAnimation(alphaAnimation);

这里就举个例子其他的都差不多,看一眼传入得参数就好了...

1.3 帧动画(对应AnimationDrawable类)

帧动画是顺序播放一组预先定义好的动画,类似于电影播放.不同于View动画,系统提供另外一个类AnimationDrawable来使用帧动画,这里注意一点就是存放帧动画XML的位置res/drawable下面!!!

1.3.1 XML中的代码

这里有一个属性说明一下

  • android:oneshot 是否只执行一次
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="true">

    <item
        android:drawable="@drawable/icon1"
        android:duration="500"/>
    <item
        android:drawable="@drawable/icon2"
        android:duration="500"/>
    <item
        android:drawable="@drawable/icon3"
        android:duration="500"/>
    <item
        android:drawable="@drawable/icon4"
        android:duration="500"/>
    <item
        android:drawable="@drawable/icon5"
        android:duration="500"/>
    <item
        android:drawable="@drawable/icon6"
        android:duration="500"/>
</animation-list>

1.3.2 代码使用

其实就是把上面定义的动画的XML当成背景设置到相应的ImageView上去,在通过getBackground取出来强转成AnimationDrawable调用start开启动画

        mIvFrame.setBackgroundResource(R.drawable.drawable_animation);
        AnimationDrawable animationDrawable = (AnimationDrawable) mIvFrame.getBackground();
        animationDrawable.start();

1.4 View动画的特殊使用场景

1.4.1 特殊使用场景

  • ViewGroup上面使用View动画
  • Activity之间的切换效果动画

1.4.1.1 LayoutAnimation 为ViewGroup设置制定动画

这个的使用场景一般是直接作用在ViewGroup 常用在ListView或者RecycleView的条目上,从而为每个子View展示一些出场效果

  • (1) 定义LayoutAnimation(位置res/anim中)
    • android:delay 表示动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5表示每个子元素都需要延迟150ms才能播放入场动画
    • android:animationOrder 表示动画元素的顺序,有三种顺序选项:normal,reverse,random在其中normal表示顺序显示;reverse表示逆向显示;random则表示随机播放入场动画
    • android:animation 为元素指定具体的入场的动画
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
                 android:animation="@anim/translate_animation"
                 android:animationOrder="normal"
                 android:delay="0.5"/>
  • (2)为ViewGroup制定android:layoutAnimation属性:android:layoutAnimation="@anim/XXX".对于ListView来说,这样ListView的item就具有出场动画了,但是这种方式适用于所有的ViewGroup
android:layoutAnimation="@anim/item_layoutanimation"

就是在相应的ViewGroup控件中加上上面的属性标签就可以了

  • (3)代码设定LayoutAnimation(通过LayoutAnimationController实现)
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXX);
        LayoutAnimationController controller = new LayoutAnimationController(animation);
        controller.setDelay(0.5f);
        controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
        View.setLayoutAnimation(controller);
        View.startAnimation(animation);//这句是开始动画用的

这里注意一点就是XXX代表的是普通的动感,而不是layoutAnimation为根节点的动画!!!

1.4.1.2 Activity的切换效果

Activity有默认的切换效果,但是这个效果我们是可以自定义的,主要用到的是overridePendingTransition(int enterAnim, int exitAnim);这个方法要在startActivity(Intent)或者finish()之后调用才会生效

动画设置

  • enterAnim Activity被打开时,所需要的资源ID

  • exitAnim Activity被暂停时,所需要都的资源ID

Fragment可也可以添加切换动画,通过FragmentTransaction中的setCustomAnimations()方法来天机啊添加切换动画,这个切换动画需要时View动画,也可以是属性动画

2.属性动画

属性动画是API11添加的新特性,和View动画不同,它对作用的对象进行了扩展,属性动画可以对任何对象做动画,甚至还可以没有对象

2.1属性动画的使用

属性动画的默认时间间隔是300ms,默认的帧率是10ms/帧

2.1.1属性动画的常用类

  • ValueAnimator
  • ObjectAnimator 继承ValueAnimator
  • AnimatorSet 动画集合
  • RevealAnimator动画效果

2.1.2举例说明

  • 改变一个对象的translationY属性,让其沿着Y轴平移一段距离
ObjectAnimator.ofFloat(mIvAnimation, "translationY", mIvAnimation.getHeight()).setDuration(1000).start();
  • 改变一个对象的背景色属性
        ValueAnimator colorAnim = ObjectAnimator.ofInt(mRvBg, "backgroundColor", 0xffff8080, 0xff8080ff);
        colorAnim.setDuration(3000);
        colorAnim.setEvaluator(new ArgbEvaluator());/*设置估值器*/
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);/*设置循环次数,这里是无限循环的*/
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);/*设置循环模式-这里设置的是逆向模式*/
        colorAnim.start();
  • 动画集合
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                ObjectAnimator.ofFloat(mIvAnimation, "rotationX", 0, 360),//X轴旋转
                ObjectAnimator.ofFloat(mIvAnimation, "rotationY", 0, 180),//Y轴旋转
                ObjectAnimator.ofFloat(mIvAnimation, "rotation", 0, -90),//旋转
                ObjectAnimator.ofFloat(mIvAnimation, "translationX", 0, 90),//x轴平移
                ObjectAnimator.ofFloat(mIvAnimation, "translationY", 0, 90),//y轴平移
                ObjectAnimator.ofFloat(mIvAnimation, "scaleX", 1, 1.5f),//X轴缩放
                ObjectAnimator.ofFloat(mIvAnimation, "scaleY", 1, 0.5f),//Y轴缩放
                ObjectAnimator.ofFloat(mIvAnimation, "alpha", 1, 0.25f, 1)//渐变
        );
        set.setDuration(500).start();

2.1.2 XML使用属性动画(位置res/animator)

  • XML中的代码

    属性动画的各个参数都比较好理解,在XML中可以定义ValueAnimation,ObjectAnimator以及AnimatorSet,其中AnimatorSet对应<Set>标签,ValueAnimator对应<animator>标签,ObjectAnimator对应<objectAnimator>标签

    • <Set>标签的详细属性

      • android:ordering动画的播放顺序,有两个参数可选;1.together代表所有子动画同时执行;2.sequentially代表所有子动画按照先后顺序执行.默认是together
    • <objectAnimator>和<animator>标签的详细属性

      • android:propertyName 表示属性动画的作用对象的属性名称
      • android:duration 表示动画的时长
      • android:valueFrom 表示属性动画的初始值
      • android:valueTo 表示属性的结束值
      • android:startOffset 表示动画的延迟时间,当动画开始后,需要延迟多少毫秒才能真正播放动画
      • android:repeatCount 表示动画的重复次数
      • android:repeatMode 表示动画的重复模式
      • android:valueType 表示Android:propertyName所制定的属性的类型,有"intType"和"floatType"两个选项,分别代表整型和浮点型,如果android:propertyName所指定的属性表示的是颜色的话,那么就不需要指定android:valueType系统会自动对颜色类型进行属性处理

这做下说明:

  • android:repeatCount 表示动画循环的次数 默认是0 当为-1的时候表示无线循环
  • android:repeatMode 表示动画的循环模式 逆向重复的时候是指当第一次播放完成的时候,第二次会倒着播放动画,第三次在从头开始播放动画,第四次在倒着播放,以此循环
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="together">

    <objectAnimator
        android:duration="300"
        android:propertyName="x"
        android:valueTo="200"
        android:valueType="intType"/>

    <objectAnimator
        android:duration="300"
        android:propertyName="y"
        android:valueTo="200"
        android:valueType="intType"/>
</set>
  • 代码中使用上面的xml
        AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.animator_anim);
        set.setTarget(mIvAnimation);
        set.start();

2.2 插值器和估值器

  • 插值器(Interpolator)

    • TimeInterpolator 时间插值器
    • LinearInterpolator 线性插值器(匀速动画)
    • AccelerateDecelerateInterpolator 加速减速插值器(动画两头慢中间快)
    • DecelerateInterpolator 减速插值器(动画越来越慢)
  • 估值器(TypeEvaluator)

    • IntEvaluator (针对帧数属性)
    • FloatEvaluator (针对浮点数属性)
    • ArgbEvaluator (针对Color属性)

2.3 属性动画的监听器

监听动画的播放过程,主要有如下两个接口 AnimatorUpdateListener,AnimatorListener

  • AnimatorListener 的定义如下:
 public static interface AnimatorListener {
        void onAnimationStart(Animator animation);
        void onAnimationEnd(Animator animation);
        void onAnimationCancel(Animator animation);
        void onAnimationRepeat(Animator animation);
    }
  • AnimatorUpdateListener 的定义如下:(它会监听整个动画过程,因为动画是由许多帧组成的,所以每播放一帧就会回调一次)
public static interface AnimatorUpdateListener {
        void onAnimationUpdate(ValueAnimator animation);
    }

2.4对任意对象使用属性动画

任意对象使用属性动画必要条件:

  • 要有相应的get/set方法,否则会报异常
  • 相应的get/set方法要能直观的从UI层面上反应出来,否则看不见效果
  • 还有一点要注意的是这个属性动画是作用在View的对象上,所以应该是View有的属性,而不是继承它的对象重新生成的属性

针对于继承的View要使用属性动画的情况,官方给出了相应的解决方案:

  • 给对象加上相应的get/set方法(如果你有权限的话)
  • 用一个类来包装原始对象,间接的提供get/set方法
/**
 * author :  贺金龙
 * create time : 2017/10/29 14:21
 * description : 包装类,为了向外面提供相应的get/set方法
 * instructions : 因为没有相应改变宽度和高度的方法,所以这里自己包装一个相应的get/set方法
 * version :
 */
public class ViewWrapper {
    private View mTargetView;


    /**
     * author :  贺金龙
     * create time : 2017/10/29 14:28
     * description : 传入相应的View,进行设置一些内容
     * instructions :
     * version :
     */
    public void setTargetView(View targetView) {
        mTargetView = targetView;
    }

    /**
     * author :  贺金龙
     * create time : 2017/10/29 14:30
     * description : 获取宽度的方法
     * instructions :
     * version :
     */
    public int getWidth() {
        return mTargetView.getLayoutParams().width;
    }

    /**
     * author :  贺金龙
     * create time : 2017/10/29 14:31
     * description : 设置宽度的方法
     * instructions : 设置相应的宽度
     * version :
     *
     * @param width 宽度
     */
    public void setWidth(int width) {
        mTargetView.getLayoutParams().width = width;
        /*重新绘制View的方法*/
        mTargetView.requestLayout();
    } 
}

***
//使用的代码
 ViewWrapper wrapper = new ViewWrapper();
 wrapper.setTargetView(view);
 ObjectAnimator.ofInt(wrapper, "width", 0, 500).setDuration(1000).start();

上面注释已经写的很详细了,说下大体的思路,传入一个View并通过LayoutParams设置相应的宽高,这样就相当于变相的设置了View的宽高了

  • 采用ValueAnimator监听动画过程,实现属性的改变
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0,500);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            /*持有一个整形的估值器*/
            private IntEvaluator mIntEvaluator = new IntEvaluator();

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                /*获取当前的动画值*/
                Integer animatedValue = (Integer) animation.getAnimatedValue();
                Log.e("done", "onAnimationUpdate: " + animatedValue);

                /*获取当前值占整个动画的比例,这个比例是0~1*/
                float animatedFraction = animation.getAnimatedFraction();

                view.getLayoutParams().width = mIntEvaluator.evaluate(animatedFraction, 0, 500);
                view.requestLayout();
            }
        });
        valueAnimator.setDuration(500);
        valueAnimator.start();

其实就是监听ValueAnimator的动画改变,用估值器进行数值的改变


2017年11月09日补充:

RevealAnimator动画效果

首先这个动画是在5.0以上的版本才能使用的

  • view 作用的View
  • centerX 动画开始的中心点X
  • centerY 动画开始的中心点Y
  • startRadius 动画开始半径
  • endRadius 动画结束半径
    public static Animator createCircularReveal(View view,
               int centerX,  int centerY, float startRadius, float endRadius) {
           return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
     }

[图片上传失败...(image-fc2cae-1510030864016)]

final View oval = this.findViewById(R.id.oval);  
oval.setOnClickListener(new View.OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Animator animator = ViewAnimationUtils.createCircularReveal(  
                oval,  
                oval.getWidth()/2,  
                oval.getHeight()/2,  
                oval.getWidth(),  
                0);  
        animator.setInterpolator(new AccelerateDecelerateInterpolator());  
        animator.setDuration(2000);  
        animator.start();  
    }  
});  
  
final View rect = this.findViewById(R.id.rect);  
rect.setOnClickListener(new View.OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Animator animator = ViewAnimationUtils.createCircularReveal(rect, 0, 0, 0,  (float) Math.hypot(rect.getWidth(), rect.getHeight()));  
        animator.setInterpolator(new AccelerateInterpolator());  
        animator.setDuration(2000);  
        animator.start();  
    }  
});  

其实这个动画和属性动画的写法基本上差不多,所以这里只是简单的实现了一些效果!

其实关于属性动画还有很多问题,这里面只是粗略的了解了一些皮毛......

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,361评论 25 707
  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,685评论 0 10
  • 做目标的意义是什么?提出假设,验证假设。用来引导,不是用来达成。调整目标,本质上是调整自己的假设。标准和预想的不一...
    青苗妈2016阅读 201评论 2 1
  • 曾经认识一对美国夫妇,有一儿一女,一家人都金发碧眼,以致于好多人以为他们是北欧人。两个孩子像洋娃娃一样萌,走在路上...
    赵静燃阅读 547评论 2 3
  • 当区块链的热度下去之后,我一直寻找可以去做的事情,换一句话说就是琢磨有什么可以挣钱的方法。今天我算是又找到了一个方...
    丁昆朋阅读 960评论 4 5