属性动画一 基本使用

一 为什么引入属性动画

  1. 补间动画只有四种(移动、缩放、旋转和淡入淡出)

补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。

  1. 补间动画只能作用于view,不能作用于canvas画出的图形

  2. 补间动画有个致命的缺陷:它只是改变了View的显示效果而已,而不会真正去改变View的属性

比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。

二 属性动画基本使用

新引入的属性动画机制已经不再是针对于View来设计的了,也不限定于只能实现移动、缩放、旋转和淡入淡出这几种动画操作,同时也不再只是一种视觉上的动画效果了。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。所以我们仍然可以将一个View进行移动或者缩放,但同时也可以对自定义View中的Point对象进行动画操作了。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。

1 ValueAnimator

ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。

基本使用

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
anim.setDuration(300);  
anim.start();

监听value的改变

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
anim.setDuration(300);  
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
        float percent = (float) animation.getAnimatedFraction();// 动画执行的百分比 0~1
    }  
});  
anim.start();

常用方法

可以使用的偏移量
ValueAnimator.ofFloat(1f);//浮点数
ValueAnimator.ofArgb(Color.BLACK);//颜色偏移
ValueAnimator.ofInt(1);//整形
ValueAnimator.ofObject();//对象
ValueAnimator.ofPropertyValuesHolder();

setStartDelay()//方法来设置动画延迟播放的时间,
setRepeatCount()//设置动画循环播放的次数
setRepeatMode()//循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示重新播放和倒序播放的意思。
animator.setDuration(5000);  // 动画播放时长

2 ObjectAnimator

相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。

一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
animator.setDuration(5000);  
animator.start();

大概原理

//1.-------------属性动画基础--------------------
iv.setTranslationX(100);
iv.setScaleX(scaleX);
iv.setAlpha(alpha);
iv.setRotation(rotation)
iv.setBackgroundColor(color);
        
//只要view里面有setXXX()方法就可以通过反射达到变化的目的
ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationX", 0f,200f);
//ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "backgroundColor", Color.RED,Color.BLUE);
oa.setDuration(500);
oa.start();

监听值变化用ValueAnimator

        //方法 2)---------------ValueAnimator---如果只需要监听值变化就用ValueAnimator---------------
        ValueAnimator animator = ValueAnimator.ofFloat(0f, 200f);
        animator.setDuration(200);
        animator.addUpdateListener(new AnimatorUpdateListener() {
            
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
                iv.setScaleX(0.5f+value/200);
                iv.setScaleY(0.5f+value/200);
            }
        });
        animator.start();

PropertyValuesHolder

//  ObjectAnimator内部使用了PropertyValuesHolder,所以这里传入PropertyValuesHolder也ok
        PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f);
        PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.5f);
        PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.5f);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv, holder1, holder2, holder3);
        animator.setDuration(200);
        animator.start();

3 动画组合

函数介绍

        animator.setRepeatCount(2);//重复两次
        animator.setRepeatCount(ValueAnimator.INFINITE);//无限重复
        animator.setRepeatMode(ValueAnimator.RESTART);// 重新开始
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animatorSet.play(animator3).with(animator2).after(animator1);//animator1在前面
        animatorSet.play(animator3).with(animator2).before(animator1);//animator1在后面
        animatorSet.playTogether(animator1, animator2, animator3);// 一起执行
        animatorSet.playSequentially(animator1, animator2, animator3);// 一个个按顺序来执行

例子:



 //-------------动画集合-----------------
        ImageView iv = new ImageView(this);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv, "translationX", 0f, 100f);
        animator1.setRepeatCount(3);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv, "alpha", 0f, 1f);
        animator2.setStartDelay(startDelay);//设置延迟执行
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv, "scaleX", 0f, 2f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(500);
        animatorSet.play(animator3).with(animator2).after(animator1);//animator1在前面
        animatorSet.play(animator3).with(animator2).before(animator1);//animator1在后面
        animatorSet.playTogether(animator1, animator2, animator3);
        animatorSet.playSequentially(animator1, animator2, animator3);// 一个个按顺序来执行
        animatorSet.start();

4 动画监听

常用监听函数

  1. 监听值变化
        final ObjectAnimator animator = ObjectAnimator.ofFloat(iv, "hehe", 0f, 100f);
        animator.setDuration(300);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 监听动画回调
                animation.getAnimatedFraction();//动画执行的百分比 0~1 //API 12+
                float value = (float) animation.getAnimatedValue();//得到0f~100f当中的这个时间点对应的值
                iv.setScaleX(0.5f + value / 200);
                iv.setScaleY(0.5f + value / 200);
                iv.setTranslationX(value);
            }
        });
        animator.start();
  1. 监听动画执行
 animator.addListener(new Animator.AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                animator.setRepeatCount(ValueAnimator.RESTART);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }
        });
  1. 监听动画执行可选部分监听
// 监听特定的函数:AnimatorListenerAdapter是一个抽象函数,实现了Animator.AnimatorListener接口
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // TODO Auto-generated method stub
                super.onAnimationEnd(animation);
            }
        });

5 插值器

Interpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非线性运动的动画效果呢?就是说动画改变的速率不是一成不变的,像加速运动以及减速运动都属于非线性运动。

决定某个时间执行哪段曲线

//6.---------插值器(加速器)Interpolater-----------
        ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationY", 0f, 1000f);
        oa.setDuration(800);
        //oa.setInterpolator(new AccelerateInterpolator(1));// 加速
        //oa.setInterpolator(new AccelerateDecelerateInterpolator());// 先加速在减速
        oa.setInterpolator(new BounceInterpolator()); // 下落弹起
        //oa.setInterpolator(new AnticipateInterpolator());// 先上再下
        //oa.setInterpolator(new CycleInterpolator(5));
        oa.start();
小球落地插值器效果
几种差值器说明.png

几种差值器的曲线图

先加速后减速效果

AccelerateDecelerateInterpolator 加速减速插值器

public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
}

加速效果

AccelerateInterpolator 加速插值器

public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    private final float mFactor;
    private final double mDoubleFactor;

    public AccelerateInterpolator() {
        mFactor = 1.0f;
        mDoubleFactor = 2.0;
    }

    public AccelerateInterpolator(float factor) {
        mFactor = factor;
        mDoubleFactor = 2 * mFactor;
    }

    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }

先回弹,再加速

AnticipateInterpolator 回荡秋千插值器

先回弹,再加速,减速,再回弹

AnticipateOvershootInterpolator

小球落地弹起效果

BounceInterpolator 弹跳插值器

正弦波

CycleInterpolator 正弦周期变化插值器

减速

DecelerateInterpolator 减速插值器

Android基于Facebook Rebound的动画效果框架Backboard demo (非常炫酷)

6 xml中使用属性动画

  • (1) XML文件位置:res/animator/filename.xml
  • (2) 文件编译后的类型:ValueAnimator, ObjectAnimator, AnimatorSet。
<set
// 执行顺序 同时 | 顺序执行
  android:ordering=["together" | "sequentially"]>

    <objectAnimator
      // 属性名,alpha translateX scale 
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        // 差值器:注意位置
        android:interpolator="@android:anim/decelerate_interpolator">
        // 模式 重复,反转重复
        android:repeatMode=["repeat" | "reverse"]
        // 值类型 ofFlaot  ofInt
        android:valueType=["intType" | "floatType"]/>

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <set>
        ...
    </set>
</set>
  • (3) 引用资源的方式:
// AnimatorSet
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
     R.anim.property_animator);
set.setTarget(myObject);
set.start();
// animator 
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);  
animator.setTarget(view);  
animator.start();  

7 TypeEvaluator 估值器

那么TypeEvaluator的作用到底是什么呢?简单来说,就是告诉动画系统如何从初始值过度到结束值。
如果是移动,Evaluator能改变移动的轨迹

Evaluator和Interpolator的区别
Evaluator(估值器)作用:决定startValue到endValue的轨迹曲线
Interpolator(差值器)作用:决定某一时间执行哪段曲线,决定每一曲线段的运动速率,重复某部分曲线段效果(小球弹起)

我们来看一下FloatEvaluator的代码实现:

public class FloatEvaluator implements TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        float startFloat = ((Number) startValue).floatValue();  
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
    }  
}  

FloatEvaluator 实现了TypeEvaluator 的evaluate方法, fraction表示执行的百分比, startValue动画开始值, endValue动画结束值,

    //------------------案例:实现自由落体抛物线效果-----------------
    /**
     * x: 匀速
     * y: 加速度 y=vt=1/2*g*t*t
     * 估值器---控制坐标PointF(x,y)
     */
        ValueAnimator valueAnimator = new ValueAnimator();
//      valueAnimator.setInterpolator(value)
        valueAnimator.setDuration(2000);
        valueAnimator.setObjectValues(new PointF(0, 0));
//      valueAnimator.setObjectValues(new PointF(0, 0),new PointF(10, 10));
        final PointF pointF = new PointF();
        //颜色估值器
//      setBackgroundColor((Integer) sArgbEvaluator.evaluate(ratio, mDiscrollveFromBgColor, mDiscrollveToBgColor));
        valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {

            @Override
            public PointF evaluate(float fraction, PointF startValue,
                    PointF endValue) {
                // 估值计算方法---可以在执行的过程当中干预改变属性的值---做效果:用自己的算法来控制
                //不断地去计算修改坐标
                //x匀速运动 x=v*t 为了看起来效果好我让t变成fraction*5
                pointF.x = 100f*(fraction*5);
                //加速度 y=vt=1/2*g*t*t
//              pointF.y = 0.5f*9.8f*(fraction*5)*(fraction*5);
                pointF.y = 10f*0.5f*9.8f*(fraction*5)*(fraction*5);
                return pointF;
            }
        });
        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
            
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF f = (PointF) animation.getAnimatedValue();
                iv.setX(f.x);
                iv.setY(f.y);
            }
        });
        valueAnimator.start();

ofObject方法使用

1 创建point估值器,不断返回坐标变换值

public class PointEvaluator implements TypeEvaluator{  
  
    @Override  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        PointF startPoint = (Point) startValue;  
        PointF endPoint = (Point) endValue;  
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());  
        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());  
        PointF point = new Point(x, y);  
        return point;  
    }  
} 

2 通过ofObject使用刚刚创建的估值器,从point1 到point2的移动

Point point1 = new Point(0, 0);  
Point point2 = new Point(300, 300);  
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);  
anim.setDuration(5000);  
anim.start();  

动态改变View的颜色

--------------------------------------------------------------------------
public class MyAnimView extends View {  
  
    private String color;  
  
    public String getColor() {  
        return color;  
    }  
  
    public void setColor(String color) {  
        this.color = color;  
        mPaint.setColor(Color.parseColor(color));  
        invalidate();  
    }  
}
--------------------------------------------------------------------------
ObjectAnimator anim = ObjectAnimator.ofObject(myAnimView, "color", new ArgbEvaluator(),   
    "#0000FF", "#FF0000");  
anim.setDuration(5000);  
anim.start(); 

参考文档
Android属性动画完全解析(上),初识属性动画的基本用法

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

推荐阅读更多精彩内容

  • 接下来的两篇文章会介绍 属性动画 相关的知识,如下图所示。本篇文章会介绍下图中绿色相关的知识。 1. 简介 相比视...
    lijiankun24阅读 634评论 0 0
  • 写的非常好,强烈推荐给大家 转载请注明出处:http://blog.csdn.net/guolin_blog/ar...
    天天大保建阅读 779评论 0 1
  • 1.介绍 Android系统为我们提供了三种动画效果的实现方式: 补间动画(Tween Animation):只能...
    容华谢后阅读 2,922评论 3 22
  • 我常幻想自己是一个功夫了得的女英雄 不 女痞子 一定要看起来放荡不羁自由散漫 还要配上帅气男主标配的犀利眼神和冷峻...
    SunNy_Monologue阅读 229评论 0 0
  • 面对2017年的职业迷惑,比往年更深的就是让自己觉得一无是处,极其悲观的时候会觉得所有行业都不感兴趣,都没意思,眼...
    斯菲阅读 265评论 0 1