美文网首页自定义view
android 动画系列三 属性动画(PropertyAnima

android 动画系列三 属性动画(PropertyAnima

作者: 赫丹 | 来源:发表于2018-09-20 17:34 被阅读107次

一、概述

  • 属性动画(Property Animation)是在 Android 3.0(API 11)后才提供的一种全新动画模式
  • 属性动画的出现主要是为了弥补补间动画(Tween Animation)的缺陷
  • 下面来看一下补间动画的缺陷
    1、 作用对象的局限
    只能够作用在视图View上,即只可以对一个Button、TextView、甚至是LinearLayout,或者其它继承自View的组件进行动画操作,但无法对非View的对象进行动画操作
    2、 没有改变View的属性,只是改变视觉效果
    只在屏幕绘制上的动画,控件的属性并没有改变,一个经典的问题就是一个Button从一个地方移动到另一个地方,点击事件还是在原来的地方
    3、拓展性太差
    只能写移动、缩放、旋转、渐变四种动画,以及这四种动画的组合,一旦遇到相对复杂的动画效果,即超出了上述4种动画效果,那么补间动画则无法实现

二、特点

  • 可以用在任意java对象
  • 不只是4种基本变换,还有其他动画效果,并且可以自定义动画效果

三、工作原理

  • 在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果,注意看这里,属性动画的本质不再是强调动画本身了,而是变成了数值发生器,不管你想干什么,属性动画只关心生成数值数列给你去使用,这就是属性动画拓展性的根本,只关心数值的生成
  • 具体的工作原理如下图


    微信图片_20180918145035.png
从以上的图片原理分析有三个核心类非常重要:AnimatorSet ValueAnimator ObjectAnimator
  • AnimatorSet 属性动画集合,就是把一堆动画放在一起执行,属性动画的集合提供了几种非常灵活的动画执行方式。
  • ValueAnimator 属性动画的核心:数值发生器,生成数值序列的类
  • ObjectAnimator 是ValueAnimator的子类,是对ValueAnimator操作的封装,使用起来更简便,一般都是用来对某一个对象的属性做动画的。

四、 ValueAnimator

ValueAnimator 是属性动画的根基了,是应用最广广泛的了,尤其是在自定义 view 中,ValueAnimator类中有几个核心的方法

  • ValueAnimator ofInt (int... values):返回一个int型变化的ValueAnimator
    (采用默认的整型估值器(IntEvaluator))
  • ValueAnimator ofFloat (float... values):返回一个float型变化的ValueAnimator
    (采用默认的浮点型估值器 (FloatEvaluator))
  • ValueAnimator ofArgb (int... values):返回一个颜色值变化的ValueAnimator,API LEVEL 21引入。
    (采用默认的颜色估值器 (ArgbEvaluator)
    以上三个构造方法如果传入了3个参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,以此类推
  • ValueAnimator ofObject (TypeEvaluator evaluator, Object... values):返回一个object型变化的ValueAnimator。
    (采用自定义对象估值器 (TypeEvaluator))
    从以上方法的定义上看,主要区别是四种不同类型的估值器达到返回不同效果的数值
    还是老一套,先看使用方法和效果, 使用的方式 分为 XML 设置 / Java 代码设置
4-1、ValueAnimator ofInt (int... values)
方式一、java代码设置
 //设置动画的初始值和结束值
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 5);
        //设置动画的时间
        valueAnimator.setDuration(500);
        //设置延时播放
        valueAnimator.setStartDelay(500);
        //设置动画播放重复次数,ValueAnimator.INFINITE=无限重复
        valueAnimator.setRepeatCount(0);
        //设置动画播放模式 ValueAnimator.RESTART=正序播放   ValueAnimator.REVERSE=倒叙播放
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        //将改变的值手动付给对象的属性值:通过动画的更新监听器实现
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                Log.d("DXDD", animatedValue + "");
            }
        });
        valueAnimator.start();
效果图
微信图片_20180918164044.png

从上面可以看出数值是从0-5的变化,可以看出并不是均匀分布,,这就和插值器有关系了,,看下面源码

    // The time interpolator to be used if none is set on the animation
    private static final TimeInterpolator sDefaultInterpolator =
            new AccelerateDecelerateInterpolator();

通过源码看出插值器的速率是始末速率较慢,中间加速,如果需要改变动画速率可以通过改变插值器的方法进行。从上可以看出插值器和估值器的联系。看下图分析


微信图片_20180918180239.png
方式二、xml代码设置
  • 步骤1:在路径 res/animator的文件夹里创建相应的动画 .xml文件
  • 步骤2:设置动画参数
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="5"
    android:valueType="intType"

    android:duration="500"
    android:startOffset="500"
    android:repeatCount="0"
    android:repeatMode="restart"
    android:fillBefore="true"
    android:interpolator="@android:anim/overshoot_interpolator"
    />
  • 使用方法
    ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(PropertyAnimaActivity.this, R.animator.values_int);
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        int animatedValue = (int) animation.getAnimatedValue();
                        Log.d("DXDD", animatedValue + "");
                    }
                });
                animator.start();
效果图同上,下面结合手动赋值给对象属性做个实例看看效果
  • 实现的动画效果:图片宽高放大一倍
 //设置动画的初始值和结束值(图片宽度放大一倍)
        ValueAnimator valueAnimator = ValueAnimator.ofInt(img_girl.getLayoutParams().width, img_girl.getLayoutParams().width * 2);
        //设置动画的时间
        valueAnimator.setDuration(1000);
        //设置动画播放重复次数,ValueAnimator.INFINITE=无限重复
        valueAnimator.setRepeatCount(0);
        //设置动画播放模式 ValueAnimator.RESTART=正序播放   ValueAnimator.REVERSE=倒叙播放
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        //设置插值器
        valueAnimator.setInterpolator(new LinearInterpolator());
        //将改变的值手动付给对象的属性值:通过动画的更新监听器实现
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 每次值变化时,将值手动赋值给对象的属性
                img_girl.getLayoutParams().width = (int) animation.getAnimatedValue();
                //刷新视图,即重新绘制,实现动画效果
                img_girl.requestLayout();
            }
        });
        valueAnimator.start();

 //设置动画的初始值和结束值(图片高度放大一倍)
        ValueAnimator valueAnimator = ValueAnimator.ofInt(img_girl.getLayoutParams().height, img_girl.getLayoutParams().height * 2);
        //设置动画的时间
        valueAnimator.setDuration(1000);
        //设置动画播放重复次数,ValueAnimator.INFINITE=无限重复
        valueAnimator.setRepeatCount(2);
        //设置动画播放模式 ValueAnimator.RESTART=正序播放   ValueAnimator.REVERSE=倒叙播放
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        //设置插值器
        valueAnimator.setInterpolator(new LinearInterpolator());
        //将改变的值手动付给对象的属性值:通过动画的更新监听器实现
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 每次值变化时,将值手动赋值给对象的属性
                img_girl.getLayoutParams().height = (int) animation.getAnimatedValue();
                //刷新视图,即重新绘制,实现动画效果
                img_girl.requestLayout();
            }
        });
        valueAnimator.start();
效果图
girl.gif

合并是两种动画同事播放,,感觉代码有点重复使用吧,,学习完下面的内容会有更简单的实现方法

4-2、ValueAnimator ofFloat (float... values)使用方法和效果同上,不同的地方是监听返回值是float类型,返回的类型不同主要是因为使用了不同的估值器(估值器在下面会详细介绍)
4-3、ValueAnimator ofArgb (int... values)

ValueAnimator中的ofArgb()可以帮助我们实现颜色的渐变效果,Google在API LEVEL 21之后增加了这个方法ofArgb()。通过这个方法我们更容易地实现颜色演变,通过ofArgb和ArgbEvaluator,我们可以轻松实现颜色渐变效果

java代码
 //第一种方法
        //设置初始值过度值和结束值
        ValueAnimator argbAnim = ValueAnimator.ofArgb(Color.parseColor("#ff669900"), Color.parseColor("#ff0099cc"), Color.parseColor("#ffff4444"), Color.parseColor("#ff669900"));
       //设置动画时间
        argbAnim.setDuration(2000);
        //设置匀速插值器
        argbAnim.setInterpolator(new LinearInterpolator());
        //动画监听
        argbAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                btn_Argb.setBackgroundColor((Integer) animation.getAnimatedValue());
            }
        });
        argbAnim.start();
//第二种方法
        //设置初始值过度值和结束值
        ValueAnimator argbAnim = ValueAnimator.ofInt(Color.parseColor("#ff669900"), Color.parseColor("#ff0099cc"), Color.parseColor("#ffff4444"), Color.parseColor("#ff669900"));
        //设置动画时间
        argbAnim.setDuration(2000);
        //设置估值器
        argbAnim.setEvaluator(new ArgbEvaluator());
        //设置匀速插值器
        argbAnim.setInterpolator(new LinearInterpolator());
        //动画监听
        argbAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                btn_Argb.setBackgroundColor((Integer) animation.getAnimatedValue());
            }
        });
        argbAnim.start();
效果图如下:(需要向下兼容用第二张方法即可实现)
argb.gif
4-4、ValueAnimator ofObject (TypeEvaluator evaluator, Object... values)

ofObject方法是什么意思呢?我们都知道ofInt和ofFloat都是针对Int值和Float值的变化,但是,我们只能控制一个值的变化,但是当我们需要实现多值变化时,它们就不再满足我们的需求。因为两个属性的初始值和结束值不一样,那么我们就可以将两个属性值封装到一个对象里面,那么初始值的object和结束值的object就可以包含两个属性不同的初始值和结束值了,这个时候就需要自定义估值TypeEvaluator器达到效果。介绍完估值器在进行ValueAnimator ofObject示例练习

五、估值器 (TypeEvaluator)

  • 定义:一个接口
  • 作用:设置 属性值 从初始值过渡到结束值 的变化具体数值
  • 应用场景: 协助插值器 实现非线性运动的动画效果
  • 计算方式:根据 插值器计算出当前属性值改变的百分比 & 初始值 & 结束值 来计算 当前属性具体的数值
    (如:动画进行了50%(初始值=100,结束值=200 ),那么匀速插值器计算出了当前属性值改变的百分比是50%,估值器则负责计算当前属性值 = 100 + (200-100)x50% = 150.)=初始值+动画百分比*(结束值-初始值)
系统默认提供了四种估值器,如果达不到要求那么就需要我们自定义估值器,需要自定义估值器就需要实现TypeEvaluator接口,复写evaluate()
public interface TypeEvaluator<T> {
    /**
     *
     * @param fraction  插值器getInterpolation()的返回值 
     * @param startValue 起始值.
     * @param endValue   结束值.
     * @return  T   赋给动画属性的具体数值
     *    
     */
    public T evaluate(float fraction, T startValue, T endValue);

前面介绍过插值器与估值器的关系,其实就事插值器中input 和 fraction关系:input的值决定了fraction的值:input值经过计算后传入到插值器的getInterpolation(),然后通过实现getInterpolation()中的逻辑算法,根据input值来计算出一个返回值,而这个返回值就是fraction,那么先来看一个系统的插值器:浮点型插值器:FloatEvaluator

public class FloatEvaluator implements TypeEvaluator<Number> {
    // FloatEvaluator实现了TypeEvaluator接口

    // 重写evaluate()
    public Float evaluate(float fraction, Number startValue, Number endValue) {
     // fraction:表示动画完成度(根据它来计算当前动画的值)
    // startValue、endValue:动画的初始值和结束值
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
      //计算方式:初始值+动画百分比*(结束值-初始值)
    }
  • 系统默认的估值器都有对应的计算逻辑,但对于ValueAnimator.ofObject(),并没有系统默认实现,因为对对象的动画操作复杂 & 多样,系统无法知道如何从初始对象过度到结束对象,因此我们需自定义估值器(TypeEvaluator)来告知系统如何进行从 初始对象 过渡到 结束对象的逻辑。下面示例实现一个加入购物车效果的估值器:
效果图
buy.gif
  • 如果需要达到抛物线效果,就需要自定义贝塞尔曲线数值变化的估值器

public class PointBezierTypeEvaluator implements TypeEvaluator<PointF> {
    PointF control;
    PointF mPointF = new PointF();

    public PointBezierTypeEvaluator(PointF control) {
        this.control = control;
    }
    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        return getBezierPoint(startValue, endValue, control, fraction);
    }

    /**
     * 二次贝塞尔曲线公式
     *
     * @param start   開始的数据点
     * @param end     结束的数据点
     * @param control 控制点
     * @param t       float 0-1
     * @return 不同t相应的PointF
     */
    private PointF getBezierPoint(PointF start, PointF end, PointF control, float t) {
        mPointF.x = (1 - t) * (1 - t) * start.x + 2 * t * (1 - t) * control.x + t * t * end.x;
        mPointF.y = (1 - t) * (1 - t) * start.y + 2 * t * (1 - t) * control.y + t * t * end.y;
        return mPointF;
    }
  • java实现方式

    private void clickView(View view) {
        int[] clickCoordinate = new int[2];
        int[] parentCoordinate = new int[2];
        int[] buyCoordinate = new int[2];
        //分别获取被点击view、父布局、购物车在屏幕上的坐标
        view.getLocationOnScreen(clickCoordinate);
        shopping_container.getLocationOnScreen(parentCoordinate);
        img_buy.getLocationOnScreen(buyCoordinate);

        //创建滑动的imageview并添加到父布局中
        if (moveImg == null) {
            moveImg = new ImageView(this);
            moveImg.setImageResource(R.drawable.red_ball);
            shopping_container.addView(moveImg);
        }
        moveImg.setVisibility(View.VISIBLE);
        moveImg.setX(clickCoordinate[0] - parentCoordinate[0]);
        moveImg.setY(clickCoordinate[1] - parentCoordinate[1]);

        //计算滑动imageview的三个控制点(起点、结束点、控制点)
        PointF startP = new PointF();
        PointF endP = new PointF();
        PointF controlP = new PointF();
        startP.x = clickCoordinate[0] - parentCoordinate[0];
        startP.y = clickCoordinate[1] - parentCoordinate[1];
        endP.x = buyCoordinate[0] - parentCoordinate[0] + img_buy.getLayoutParams().width / 5;
        endP.y = buyCoordinate[1] - parentCoordinate[1] + img_buy.getLayoutParams().width / 5;
        controlP.x = endP.x;
        controlP.y = startP.y;

        //执行动画
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointBezierTypeEvaluator(controlP), startP, endP);
        valueAnimator.setDuration(1000);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                                            @Override
                                            public void onAnimationUpdate(ValueAnimator animation) {
                                                PointF pointF = (PointF) animation.getAnimatedValue();
                                                moveImg.setY(pointF.y);
                                                moveImg.setX(pointF.x);
                                            }
                                        }
        );
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                moveImg.setVisibility(View.INVISIBLE);
                ++count;
                tv_num.setText(count + "");
                ScaleImage(img_buy);
            }
        });
        valueAnimator.start();
    }
  • 购物车动画效果
  private void ScaleImage(ImageView img) {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "scaleX", 1f, 0.5f, 1f);
        objectAnimator.setDuration(500);
        objectAnimator.setInterpolator(new SpringInterpolator());
        objectAnimator.start();
        ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(img, "scaleY", 1f, 0.5f, 1f);
        objectAnimator1.setDuration(500);
        objectAnimator1.setInterpolator(new SpringInterpolator());
        objectAnimator1.start();
    }
  • 以上就是自定义估值器结合ValueAnimator.ofObject()实现购物车抛物线效果
  • 从购物车动画效果代码看出 ObjectAnimator这个类的动画实现方式,下面详细介绍一下这个类

六、ObjectAnimator

上面说了ObjectAnimator是ValueAnimator的子类,是对ValueAnimator操作的封装,目的就是让我们的属性动画操作更加简单,这符合 java 简单化的思想,大伙仔细想想,简单好用就是我们码代码的终极追求之一啊,下面来看看常用属性和用法:

6-1 常用的propertyName:
  • rotationX 围绕x轴旋转
  • rotationY 围绕y轴旋转
  • rotation 围绕轴点旋转
  • translationX 在x轴方向上平移
  • translationY 在y轴方向上平移
  • scaleX 在x轴方向缩放
  • scaleY 在y轴方向缩放
  • alpha 透明度
  • width 宽度
  • height 高度
6-2 使用方法:
ObjectAnimator animator = ObjectAnimator.ofFloat(testView, "translationX", 100);
animator.setDuration(600);
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.setRepeatCount(1);
animator.start();
  • 这是一个位移动画,像右移动100px,需要达到其他的效果,方法同上,只需修改动画属性即可。

七、path动画

5.0版本属性动画中添加了一个path动画,可以让 view 沿着 path 的路径做动画
  • 代码
  ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, View.X, View.Y, path_view.getPath());
                animator.setDuration(1000);
                animator.setRepeatMode(ObjectAnimator.REVERSE);
                animator.setRepeatCount(1);
                animator.start();
  • 有4个参数,第一个是目标 view,后面2个是需要操作的 view 的位置坐标,最后是 path
  • 效果图


    path.gif

八、AnimatorSet 动画集合

8-1在AnimatorSet中给为我们提供了两个方法playSequentially和playTogether
  • playSequentially表示所有动画依次播放
  • playTogether表示所有动画一起开始
    playTogether和playSequentially在激活动画后,控件的动画情况与它们无关,它们只负责定时激活控件动画。 playSequentially只有上一个控件做完动画以后,才会激活下一个控件的动画,如果上一控件的动画是无限循环,那下一个控件就无法做动画了。
  • 使用示例:
ObjectAnimator objectAnimator01 = ObjectAnimator.ofArgb(ivImage05, "BackgroundColor",
                getResources().getColor(R.color.colorPrimary),
                getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));
        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage05, "TranslationY", 0, 300, 0);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage06, "TranslationY", 0, 400, 0);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage07, "TranslationY", 0, 500, 0);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage08, "TranslationY", 0, 600, 0);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(objectAnimator01, objectAnimator02, objectAnimator03, objectAnimator04, objectAnimator05);
        animatorSet.setDuration(2000);
        animatorSet.start();
8-2 AnimatorSet.Builder(自由设置动画顺序)

AnimatorSet.Builder用于实现playTogether和playSequentially无法实现的效果,可以实现非常自由的组合动画,比如有三个动画A,B,C想先播放C然后同时播放A和B,利用playTogether和playSequentially是没办法实现的,但利用AnimatorSet.Builder却可以轻易实现。

AnimatorSet.Builder常用方法:
方法 说明
public Builder play(Animator anim) 表示要播放哪个动画 AnimatorSet中的play方法是获取AnimatorSet.Builder对象的唯一途径
public Builder with(Animator anim) 和前面动画一起执行
public Builder before(Animator anim) 执行前面的动画后才执行该动画
public Builder after(Animator anim) 执行先执行这个动画再执行前面动画
public Builder after(long delay) 延迟n毫秒之后执行动画

play(Animator anim)表示当前在播放哪个动画,另外的with(Animator anim)、before(Animator anim)、after(Animator anim)都是以play中的当前所播放的动画为基准的。
当play(playAnim)与before(beforeAnim)共用,则表示在播放beforeAnim之前,先播放playAnim动画;同样,当play(playAnim)与after(afterAnim)共用时,则表示在在播放afterAnim动画之后,再播放playAnim动画。

  • 使用示例
/**
     * 按照自定义顺序播放动画
     * 首先ivImage09的颜色变化、位移和ivImage09,同时发生
     * 等待前面的动画播放完后 ivImage11,ivImage12才开始动画
     *
     */

 ObjectAnimator objectAnimator01=ObjectAnimator.ofArgb(ivImage09, "BackgroundColor",
                getResources().getColor(R.color.colorPrimary),
                getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));
        ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
        ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
        ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
        ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(objectAnimator01).with(objectAnimator02).with(objectAnimator03).before(objectAnimator04).before(objectAnimator05);
        animatorSet.setDuration(2000);
        animatorSet.start();
8-3 PropertyValuesHolder
  • 多属性动画同时工作管理类。有时候我们需要同时修改多个属性,那就可以用到此类,具体如下:
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);  
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);  
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();

九、ViewPropertyAnimator

9-1Google官方在Android 3.1系统中补充了ViewPropertyAnimator类,这个类便是专门为View动画而设计的。当然这个类不仅仅是为提供View而简单设计的,它存在以下特点:

1、专门针对View对象动画而操作的类。
2、提供了更简洁的链式调用设置多个属性动画,这些动画可以同时进行的。
3、拥有更好的性能,多个属性动画是一次同时变化,只执行一次UI刷新(也就是只调用一次invalidate,而n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)。
4、每个属性提供两种类型方法设置scaleX()/scaleXBy()。
5、该类只能通过View的animate()获取其实例对象的引用

9-2 每个属性,两种类型方法设置:

rotationX(20) 改变到某个值。 旋转到20度。再调用一次的话,由于已经到20度的位置,便不在有变化。
rotationXBy(20) 改变某个值的量。 旋转20度。再调用一次的话,继续旋转20度,到40度的位置。

9-3常见设置
view.animate()//获取ViewPropertyAnimator对象
                        //动画持续时间
                        .setDuration(5000)

                        //透明度
                        .alpha(0)
                        .alphaBy(0)

                        //旋转
                        .rotation(360)
                        .rotationBy(360)
                        .rotationX(360)
                        .rotationXBy(360)
                        .rotationY(360)
                        .rotationYBy(360)

                        //缩放
                        .scaleX(1)
                        .scaleXBy(1)
                        .scaleY(1)
                        .scaleYBy(1)

                        //平移
                        .translationX(100)
                        .translationXBy(100)
                        .translationY(100)
                        .translationYBy(100)
                        .translationZ(100)
                        .translationZBy(100)

                        //更改在屏幕上的坐标
                        .x(10)
                        .xBy(10)
                        .y(10)
                        .yBy(10)
                        .z(10)
                        .zBy(10)

                        //插值器
                        .setInterpolator(new BounceInterpolator())//回弹
                        .setInterpolator(new AccelerateDecelerateInterpolator())//加速再减速
                        .setInterpolator(new AccelerateInterpolator())//加速
                        .setInterpolator(new DecelerateInterpolator())//减速
                        .setInterpolator(new LinearInterpolator())//线性

                        //动画延迟
                        .setStartDelay(1000)

                        //是否开启硬件加速
                        .withLayer()

                        //监听
                        .setListener(new Animator.AnimatorListener() {
                            @Override
                            public void onAnimationStart(Animator animation) {
                                Log.i("MainActivity", "run: onAnimationStart");
                            }

                            @Override
                            public void onAnimationEnd(Animator animation) {
                                Log.i("MainActivity", "run: onAnimationEnd");
                            }

                            @Override
                            public void onAnimationCancel(Animator animation) {
                                Log.i("MainActivity", "run: onAnimationCancel");
                            }

                            @Override
                            public void onAnimationRepeat(Animator animation) {
                                Log.i("MainActivity", "run: onAnimationRepeat");
                            }
                        })

                        .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                Log.i("MainActivity", "run: onAnimationUpdate==");
                            }
                        })

                        .withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                Log.i("MainActivity", "run: end");
                            }
                        })
                        .withStartAction(new Runnable() {
                            @Override
                            public void run() {
                                Log.i("MainActivity", "run: start");
                            }
                        })

                        .start();

相关文章

网友评论

    本文标题:android 动画系列三 属性动画(PropertyAnima

    本文链接:https://www.haomeiwen.com/subject/nftrnftx.html