属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator

属性动画在API 11推出,目的是弥补帧动画和补间动画的不足,回顾其常用的使用方式。

      • 使用ViewPropertyAnimator
      • 使用ObjectAnimator
        • ofFloat方法
        • ofInt方法
        • ofArgb方法
        • ofObject方法
        • ofPropertyValuesHolder方法
          • ofKeyframe
        • addListener
        • addUpdateListener
        • 其他方法

使用ViewPropertyAnimator

ViewPropertyAnimator可以直接使用View对象进行链式调用,能够比较方便的创建动画。

编写一个简单的例子,布局:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/bt_animation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:text="动画"
        />

RelativeLayout>

设置动画:

        Button btn = findViewById(R.id.bt_animation);
        float x = btn.getTranslationX();
        btn.animate()//获取ViewPropertyAnimator对象
                .translationX(x)//从当前位置移动
                .translationX(400)//移动到400px
                .setDuration(2000)//动画执行时间
                .start();//开始执行动画,不调用此方法同样会执行

运行效果:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第1张图片
实际上btn.animate()返回的就是ViewPropertyAnimator对象。
ViewPropertyAnimator对象还有一些其他的常用方法:

view.animate()//获取ViewPropertyAnimator对象
                //位移
                .translationX(100)
                .translationXBy(100)
                .translationY(100)
                .translationYBy(100)
                .translationZ(100)//Z轴移动,API 21 添加
                .translationZBy(100)//API 21 添加
                //改变坐标
                .x(100)
                .xBy(100)
                .y(100)
                .yBy(100)
                //改变透明度
                .alpha(0.1f)
                .alphaBy(0.1f)
                //改变透明度
                .scaleX(0.1f)
                .scaleXBy(0.1f)
                .scaleY(0.1f)
                .scaleYBy(0.1f)
                //旋转
                .rotation(180)
                .rotationX(180)
                .rotationBy(180)
                .rotationY(180)
                .rotationYBy(180)
                //持续时间
                .setDuration(1000)
                .withStartAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                })//动画开始时执行runnable,API 16添加
                .withEndAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                })//动画结束时执行runnable,API 16添加

                .withLayer()//硬件加速,API 16添加

                .setStartDelay(1000)//执行延迟
                //设置插值器
                .setInterpolator(new LinearInterpolator())
                //设置更新监听
                .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {

                    }
                })
                //动画监听
                .setListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {

                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                })
                .start();

其中不带By和带By的方法区别:

 .translationX(100)//直接移动到指定位置
 .translationXBy(100)//在之前的位置基础上移动指定距离
//其他方法以此类推...

使用ObjectAnimator

ObjectAnimator其实是属性动画最常用的类,基本能满足日常动画编写。ObjectAnimator封装了一系列的of方法,根据实际情况来选用。
API 27of系列方法:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第2张图片

ofFloat方法

首先看一个简单的例子:

        Button btn = findViewById(R.id.bt_animation);
        float x = btn.getTranslationX();
        ObjectAnimator animator = ObjectAnimator.ofFloat(btn, "translationX", x, 400);
        animator.setDuration(2000);
        animator.start();

说明其参数意义:
- btn为执行动画的对象,这里是Button按钮;
- translationX为需要操作的动画属性;
- x,400 为操作的起始值和结束值,中间还可插入一系列的数值,来满足动画的灵活变化;
同时ObjectAnimator单独提供了setFloatValues(float... values)方法,但是如果使用此方法
会将之前设置的第一组values替换掉,需要注意一下。

ObjectAnimator还可以设置插值器:

       Button btn = findViewById(R.id.bt_animation);
        float x = btn.getTranslationX();
        ObjectAnimator animator = ObjectAnimator.ofFloat(btn, "translationX", x, 400);
        animator.setInterpolator(new AccelerateInterpolator());//加速插值器
        animator.setDuration(1000);
        animator.start();

执行效果:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第3张图片
API 27为止包含的系统插值器:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第4张图片
使用Property封装的方法:

        ObjectAnimator animator = ObjectAnimator.ofFloat(btn,
                Property.of(Button.class, Float.class, "translationX"),
                x, 400);
        animator.setDuration(2000);
        animator.start();

另外API 21 增加了Path对象,这样可以执行更为复杂灵活的动画效果:

        Button btn = findViewById(R.id.bt_animation);
        Path path = new Path();
        path.moveTo(btn.getX(),btn.getY());
        path.lineTo(400,400);
        //API 21 添加
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ObjectAnimator animator = ObjectAnimator.ofFloat(btn, "translationX", "translationY", path);
            animator.setDuration(2000);
            animator.start();
        }

说明下该方法的参数:

ObjectAnimator.ofFloat(Object target, String xPropertyName, String yPropertyName,
            Path path)
  • target动画执行的对象
  • xPropertyNameX轴坐标
  • yPropertyNameY轴坐标
  • Path绘制动画路径类

API 21也可以使用PropertyPath参数的方法:

            ObjectAnimator animator = ObjectAnimator.ofFloat(btn,
                    Property.of(Button.class, Float.class, "translationX"),
                    Property.of(Button.class, Float.class, "translationY"),
                    path);
            animator.setDuration(2000);
            animator.start();

使用带TypeEvaluator估值器参数的方法:

       ObjectAnimator animator = ObjectAnimator.ofObject(btn, "translationX", new FloatEvaluator(), x, 400);
        animator.setDuration(2000);
        animator.start();

API 27为止,系统已经实现的估值器:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第5张图片

ofInt方法

基本同ofFloat方法一致。

ofArgb方法

API 21ObjectAnimator单独提供ofArgb方法用于方便进行颜色动画的过渡计算:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ObjectAnimator
                    .ofArgb(btn, "backgroundColor",
                            Color.parseColor("#ff0000"),//红色
                            Color.parseColor("#0000ff"))//蓝色
                    .setDuration(2000)
                    .start();
        }

执行由红变蓝的效果:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第6张图片

ofObject方法

另外ObjectAnimator还有ofObject的一些方法:

        ObjectAnimator
                .ofObject(btn,"translationX",new FloatEvaluator(),x,400)
                .setDuration(2000)
                .start();

上面这这段代码同样可以实现平移效果,看下该方法的参数:

public static ObjectAnimator ofObject(Object target, String propertyName,
            TypeEvaluator evaluator, Object... values)
  • target动画执行的对象
  • PropertyName属性名
  • TypeEvaluator估值器
  • values动画执行的可变参数

    这里需要注意的是TypeEvaluator中的evaluate()方法返回类型必须和values的参数类型一致,因为这里没有进行泛型约束,因此需要特别注意,该方法主要可以用于自定义的TypeEvaluatorvalues,因此在执行动画过程中,需要保证类型一致。

ofPropertyValuesHolder方法

ObjectAnimator还提供了非常重要的ofPropertyValuesHolder系列方法,使用PropertyValuesHolder参数可以使多个动画同时执行:

        PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX", x, 400);
        PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationY", y, 400);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(btn, p1, p2);
        animator.setDuration(2000);
        animator.start();

PropertyValuesHolder其实就是封装了要执行动画改变的属性和一系列的变化值,并且也拥有和ObjectAnimator类似的各种ofIntofFloatofObject等方法。

ofKeyframe

ofKeyframe的方法可以设置动画的关键帧:

        Keyframe k1 = Keyframe.ofFloat(0, x);
        Keyframe k2 = Keyframe.ofFloat(0.5f, 100);
        Keyframe k3 = Keyframe.ofFloat(1f, 400);

        PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX", k1, k2, k3);
        ObjectAnimator.ofPropertyValuesHolder(btn,holder).setDuration(2000).start();

Keyframe.ofFloat(float fraction, float value)方法中fraction代表动画执行的进度(0-1之间),value代表这个进度需要执行的数值,也就是一帧的意思。
看下执行效果:
属性动画使用解析(一):ViewPropertyAnimator和ObjectAnimator_第7张图片
另外Keyframe也可以设置插值器,和ObjectAnimator比较类似,这里不再列出。
但是需要注意的是如果使用Keyframe则必须至少有2帧添加到PropertyValuesHolder中,否则会抛出异常:
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1

addListener

可以添加动画周期中的监听回调:

objectAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {

                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });

如果直接使用Animator.AnimatorListener参数,需要实现的方法较多,可以选择AnimatorListenerAdapter,它实现了Animator.AnimatorListener接口,可以有选择的实现需要的接口。

addUpdateListener

该方法可以获取更新中的ValueAnimator对象,从而获取其中包含的相关信息,编写业务逻辑。

objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                }
            });

其他方法

setRepeatCount:就是设置动画执行次数;
setRepeatMode:设置重复模式 RESTART,REVERSE,INFINITE;
setStartDelay:设置动画执行延迟;
其他还有些方法,不一一分析了。

你可能感兴趣的:(Android,属性动画,ObjectAnimator)