Android Property Animation

概述


  • 属性动画,顾名思义-动态改变对象的属性,以此变化来产生某种效果。 这里的对象可是任何对象,并不限定是View控件。

  • 属性动画是Android 3.0(API 11)增加的,为何增加?有何意义?

    • 你一定还记得在view animation 中,交互不友好(比如view的位置改变了,但是点击事件还在原来的位置)
    • view animation 能让view动起来的效果有限,属性动画可是打着能改变任何对象的任何属性出场的,这样就可以实现复杂高级效果了。
  • 系统为我们提供了属性动画哪些用法?出了具体表现在这些类,也支持XML中定义使用。

    • ObjectAnimator
    • PropertyHolder
    • ValueAnimator
    • AnimatorSet
    • Animator.AnimatorListener
    • ValueAnimator.AnimatorUpdateListener
  • 属性动画中也要用到view动画中的差值器等API,也独有估值器

ObjectAnimator


ObjectAnimator继承关系

在这个类中,通过调用ObjectAnimator的工厂方法,传入对应的参数即可,举个简单的用法来看具体怎么使用

属性动画1.gif

这样的效果用属性动画也是非常容易实现的

 ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
 // 指定一个时间差值器(TimeInpolator),ObjectAnimator默认的是LinearInpolator
 objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
 objectAnimator1.setDuration(1000);
 objectAnimator1.start();

关于ofFloat(Object target, String propertyName, float... values)
第一个参数是要操纵的对象,第二个是操纵对象的属性名,第三个是一个可变数组参数,表示属性的取值变化的过程

列举view的一些常见可以直接用的属性值
view偏移量: translationX 、translationY
view2D和3D旋转角度: rotation、rotationX、rotationY
view的2D缩放比例: scaleX、 scaleY
view的旋转和缩放的中心点,默认是view的中心点:pivotX、pivotY
view的坐标: x 、y
view的透明度: alpha

值得注意的是ObjectAnimator

  • 操纵的属性必须具有set<propertyName>(),因为ObjectAnimator在动态改变属性的过程中,会去通过set方法来改变这个属性。如果操纵的属性没有set方法,官方给出三种建议:
    • 如果你有权限的话就去给这个属性添加一个set方法
    • 可以通过自定义一个属性类或者包装类,来间接给这个属性增加set方法
    • 使用ValueAnimator来代替
  • 对于这个可变参数,values...如果仅仅设置了一个参数,会被认为这个值是变化过程的结束值。此刻ObjectAnimator会自动去通过get<propertyName>()来获得变化的起始值,这时就要求操作的属性必须具有get方法

这里我们举个例子,操作一个自定义的对象

 public class Person {
    private int age;

    public void setAge(int age) {
        this.age = age;
        Log.d("age", "set年龄" + age);
    }

    public int getAge() {
        Log.d("age", "get年龄" + age);
        return age;

    }
}

这个时候我们去动画的改变它

 ObjectAnimator objectAnimator;
 // 1.属性动画可以对任意一个对象的属性动态改变
 objectAnimator = ObjectAnimator.ofInt(new Person(), "age",5,  8);
 objectAnimator.start();

观察这个时候的log

log1

和我们预想的一样,动态改变了这个年龄值,哈哈

如果我们对可变参数只设置一个参数呢?

 ObjectAnimator objectAnimator;
// 1.属性动画可以对任意一个对象的属性动态改变
objectAnimator = ObjectAnimator.ofInt(new Person(), "age", 4);
objectAnimator.start();

这个时候的log 显示表明调用了get方法获得初始值

log2

虽然上面这个改变属性值没有实际意义,但是很清晰的展示了属性动画的魅力和变化过程。

你对为什么一个数值打印那么多遍感到很奇怪?
其实这就是属性动画中有估值器(Evaluator)这个概念,这里我给采用的是ofInt 对应的其实是IntEvaluator,这是ObjectAnimator内部会去判断,可以去源码中查看。
同理如果ofFloat对应的就是FloatEvaluator
当然你也可以ofObject传入自己想要的估值器

那么这个时候你把Personage属性改成float, 并且动画采用ofFloat,结果你会发现会一步一步接近最后的值。

反复调用set方法,一步步接近终值

PropertyValuesHolder


如果同时改变多个属性呢?

可以直接构造多个ObjetAnimator 然后调用start. 因为他们是异步的,这些动画会同时执行

  objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
  objectAnimator1.setDuration(1000);
  ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
  objectAnimator2.setInterpolator(new AccelerateDecelerateInterpolator());
  objectAnimator2.setDuration(1000);
  ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
  objectAnimator3.setInterpolator(new AccelerateDecelerateInterpolator());
  objectAnimator3.setDuration(2000);
  objectAnimator1.start();
  objectAnimator2.start();
  objectAnimator3.start();;

还可以使用PropertyValuesHolder,然后调用的ObjectAnimator.ofPropertyValuesHolder

PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0f,imageview.getWidth());
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationY",0f,imageview.getHeight());
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("rotationX",0f,360f);
ObjectAnimator.ofPropertyValuesHolder(imageview, p1,p2,p3).setDuration(2000).start();

在上面的例子中,那如果我想控制他们的播放顺序呢?

AnimatorSet


同时X,Y平移后旋转

这个效果是先同时x和y方向平移动画,然后在执行旋转

    ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
    ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
    ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
    AnimatorSet set = new AnimatorSet();
    set.setDuration(2000);
    set.setInterpolator(new LinearInterpolator());
    //set.playTogether(objectAnimator1,objectAnimator2, objectAnimator3);
    //set.playSequentially(objectAnimator1,objectAnimator2, objectAnimator3);
    set.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3); objectAnimator3);
    set.start();

可以将注释部分观察效果。AnimatorSet需要说明几点:

  • playSequentially是单独顺序播放
  • play配合withbeforeafter来按照这些规则播放动画
  • playTogether 动画同时播放

ValueAnimator的使用


通过上面的那个类关系图,ValueAnimatorObjectAnimator的父类,实际上ObjectAnimator是更加具体化了ValueAnimator,实现了一系列的既定效果,更加方便的使用。那么上文提到如果一个属性没有set方法可以用ValueAnimator来代替.

什么意思呢?其实就是说ValueAnimator,它并不要求你非要指定什么属性,注重的是值的变化,然后可以监听这些值的变化过程,从而自己来根据这些值,产生你自己需要的效果。比如你要做一个计时器,这个时候你可以ofInt在监听里面去设置UI 显示倒计时的数值即可。

这里看一下如何监听等常规思路:

ValueAnimator valueAnimator = ValueAnimator.ofInt(1,15);// ValueAnimator ,ofInt,ofFloat,ofObject
   
    // valueAnimator.setEvaluator(new IntEvaluator()); // 设置估值器
    valueAnimator.setEvaluator(new TypeEvaluator<Integer>() {
        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            // 这里自定义了一个估值器,就是在int估值器的基础上加一个1
            int startInt = startValue;
            return (int)(startInt + fraction * (endValue - startInt)+1);
        }
    });
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
           Log.d("smart","变化的值:" +animation.getAnimatedValue());
        }
    });
    valueAnimator.setDuration(3000);
    valueAnimator.start();

估值器

  • 系统定义的估值器:

    • IntEvaluator 计算整型
    • FloatEvaluator 计算float型
    • ArgbEvaluator 计算颜色
    • TypeEvaluator 是一个接口,自定义估值器需要实现它
  • 如何自定义一个估值器

      public interface TypeEvaluator<T> {
    
          public T evaluate(float fraction, T startValue, T endValue);
      }
    

    实现这个接口,确定泛型的返回值T。

至此 ,属性动画的基本概念叙述完毕!

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

推荐阅读更多精彩内容