zoukankan      html  css  js  c++  java
  • Android动画系列之属性动画

    原文首发于微信公众号:jzman-blog,欢迎关注交流!

    属性动画相较帧动画和补间动画更强大,帧动画和补间动画只能应用于 View 及其子类,而属性动画可以修改任何对象的属性值,属性值可在指定的一段时间内自动改变,根据对象属性值的变化进而实现更复杂的动画。

    1. 属性动画的常用设置
    2. ValueAnimator
    3. ObjectAnimator
    4. 关键帧
    5. 插值器和估值器

    属性动画的常用设置

    下面是属性动画的常用设置,具体如下:

    //设置属性动画持续时间
    animator.setDuration(2000);
    //设置属性插值器
    animator.setInterpolator(new AccelerateInterpolator());
    //设置属性动画重复播放模式
    animator.setRepeatMode(ValueAnimator.REVERSE);
    //设置属性动画重复播放次数
    animator.setRepeatCount(0);
    //设置属性动画延时播放的时间
    animator.setStartDelay(0);
    //设置属性动画估值器,用于控制最终属性值(API22)
    animator.setCurrentFraction(0.5f);
    //设置当前播放时间,其值在Duration范围之内
    animator.setCurrentPlayTime(1000);
    //设置属性动画估值器,用于控制最终属性值
    animator.setEvaluator(new IntEvaluator());
    //设置属性动画监听
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            Log.i(TAG, animation.getAnimatedValue() + "");
            //
        }
    });
    //...
    
    

    ValueAnimator

    ValueAnimator 提供了一个简单的计时引擎,用于执行动画时根据设置的时长以及其他属相完成动画值的计算,然后就可以将动画值设置到合适的目标对象上,使用的插值器默认时 AccelerateDecelerateInterpolator,表示动画开始和结束时较慢,中间加速完成动画,下面是源码中默认的插值器,具体如下:

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

    在 ValueAnimator 中已经内部处理了一些估值器 IntEvaluator 和 FloatEvaluator,也就是说如果使用的时 ofInt 和 ofFloat 方法作为动画的属性值,那么 ValueAnimator 会自动处理 int 和 float 值的变化,在源码中找了一下,这部分内容在 PropertyValuesHolder 这个类中,具体如下:

    void init() {
        if (mEvaluator == null) {
            // We already handle int and float automatically, but not their Object
            // equivalents
            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
                    (mValueType == Float.class) ? sFloatEvaluator :
                    null;
        }
        if (mEvaluator != null) {
            // KeyframeSet knows how to evaluate the common types - only give it a custom
            // evaluator if one has been set on this class
            mKeyframes.setEvaluator(mEvaluator);
        }
    }
    

    ValueAnimator 可以使用代码创建,也可以使用 xml 创建,下面以平移动画为例说明 ValueAnimator 的使用方式,其他如缩放、旋转等使用方式类似。

    使用代码创建
    private void translation(){
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
        valueAnimator.setDuration(2000);
        valueAnimator.setInterpolator(new AccelerateInterpolator());
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        valueAnimator.setRepeatCount(0);
        valueAnimator.setStartDelay(0);
    //    valueAnimator.setCurrentFraction(0.5f);
    //    valueAnimator.setCurrentPlayTime(1000);
        valueAnimator.setEvaluator(new IntEvaluator());
    
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.i(TAG, animation.getAnimatedValue() + "");
                int x = (int) animation.getAnimatedValue();
                ivImage.setTranslationX(x);
                ivImage.setTranslationY(x);
            }
        });
    
        valueAnimator.start();
    }
    
    使用xml创建

    在 res/animator 文件夹下创建 test_animator.xml 文件,文件内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <animator xmlns:android="http://schemas.android.com/apk/res/android"
        android:valueFrom="0"
        android:valueTo="100"
        android:valueType="intType"
    
        android:duration="2000"
        android:startOffset ="0"
        android:repeatMode = "reverse"
        android:repeatCount = "0"
        android:interpolator = "@android:anim/accelerate_interpolator">
    </animator>
    

    然后在 Activity 中获取 ValueAnimator,设置目标对象,启动动画即可,具体如下:

    private void translation(){
        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.test_animator);
        animator.setTarget(ivImage);
        animator.start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.i(TAG, animation.getAnimatedValue() + "");
                int x = (int) animation.getAnimatedValue();
                ivImage.setTranslationX(x);
                ivImage.setTranslationY(x);
            }
        });
    }
    
    测试效果

    这里使用 ValueAnimator 来实现平移动画,测试效果如下:

    ValueAnimator

    ObjectAnimator

    ObjectAnimator 是 ValueAnimator 的子类,可在目标对象上支持动画属性的设置,在其构造方法中通过参数指定目标对象以及所对应动画属性的名称,然后会相应的执行对应的动画属性的 setter 方法来最终完成动画的执行,也就是说属性动画 ObjectAnimator 最终调用目标对象的 setter 方法完成目标对象属性值的变化,然后相应的改变目标对象的属性,从而实现目标对象的动画效果,下面以透明度变化来介绍 ObjectAnimator 的基本使用,代码参考如下:

    private void alpha(){
        ObjectAnimator animator = ObjectAnimator.ofFloat(ivImage,"alpha",1f,0,1f);
        animator.setDuration(3000);
        //其他属性动画设置
        //...
        animator.start();
    }
    

    下面是测试效果,如下图所示:

    属性动画-透明度

    至于平移、旋转、缩放动画实现方式基本如上,这里不再赘述,其对应的 setter 方法对应关系如下:

    属性 作用 对应方法
    Alpha 控制View的透明度 setAlpha
    TranslationX 控制X方向的位移 setTranslationX
    TranslationY 控制Y方向的位移 setTranslationY
    ScaleX 控制X方向的缩放倍数 setScaleX
    ScaleY 控制Y方向的缩放倍数 setScaleY
    Rotation 控制以屏幕方向为轴的旋转度数 setRotation
    RotationX 控制以X轴为轴的旋转度数 setRotationX
    RotationY 控制以Y轴为轴的旋转度数 setRotationY

    ObjectAnimator 提供了很多的 ofXxx() 方法来方面设置属性动画,如下图所示:

    属性动画-ofXxx()

    可根据不同的动画需求使用 ObjectValueAnimator 不同 ofXxx() 方法来实现相应的动画。

    关键帧

    这里简单说一下关键帧的使用,顾名思义关键帧就是在某个固定时刻上定义具体的属性值,为定义的将按照估值器返回的值返回属性值,属性动画中的关键帧使用方式如下:

    /**
     * 关键帧的使用
     */
    private void keyFrame(){
        Keyframe keyframe1 = Keyframe.ofFloat(0,0);
        Keyframe keyframe2 = Keyframe.ofFloat(0.25f,300);
        //每个KeyFrame可设置自己的插值器
        keyframe2.setInterpolator(new AccelerateInterpolator());
        Keyframe keyframe3 = Keyframe.ofFloat(0.75f,100);
        Keyframe keyframe4 = Keyframe.ofFloat(1,400);
        PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(ivImage,holder);
        animator.setDuration(3000);
        animator.start();
    }
    

    看一下添加关键帧之后对普通平移动画的改变,实现测试效果如下:

    keyFragme.gif

    插值器和估值器

    • 插值器(TimeInterpolator) 表示的是整个动画期间动画的变化规律,如加速、减速等。

    Android 内置许多插值器,这些插值器基本涵盖了实际开发中的大部分情况,具体如下:

    插值器

    如果内置的插值器不满足需求,也可以自定义插值器。

    • 估值器(TypeEvaluator)表示的是在整个动画期间各时刻属性值的具体变化。

    这里自定义一个估值器来实现一个 View 沿正弦曲线运动,自定义估值器如下:

    /**
     * 自定义估值器
     * Point封装了坐标x和y
     */
    public class SineTypeValue implements TypeEvaluator<Point> {
        @Override
        public Point evaluate(float fraction, Point startValue, Point endValue) {
            //y = sinA
            float distance = fraction * (endValue.getX() - startValue.getX());
            float x = startValue.getX() + distance;
            float y = startValue.getY() + (float) Math.sin(distance / 100 * Math.PI) * 100;
            Point point = new Point();
            point.setX(x);
            point.setY(y);
            return point;
        }
    }
    

    然后给动画设置该估值器,监听动画属性设置 View 的位置即可实现一个 View 沿正弦曲线运动,使用方式如下:

    /**
     * 自定义估值器的使用
     * 正弦运动的估值器
     */
    private void sina(){
        Point startPoint = new Point(ivImage.getX(),ivImage.getY());
        Point endPoint = new Point(ivImage.getX()+500,ivImage.getY());
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new SineTypeValue(), startPoint, endPoint);
        valueAnimator.setDuration(5000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.i(TAG, animation.getAnimatedValue() + "");
                Point point = (Point) animation.getAnimatedValue();
                ivImage.setX(point.getX());
                ivImage.setY(point.getY());
            }
        });
        valueAnimator.start();
    }
    

    测试效果如下:

    自定义估值器

    可以关注公众号:躬行之(jzman-blog),一起交流学习。

  • 相关阅读:
    git 教程
    darknet_ros 踩坑与解决办法
    相机与手臂的校准
    相机的内参外参标定
    VNC windous->linux
    12306 官网硬卧下铺的选择
    /usr/bin/ld: cannot find -lopencv_dep_cudart
    在Windows上安装GPU版Tensorflow
    机器学习基础
    [设计模式]行为型设计模式
  • 原文地址:https://www.cnblogs.com/jzmanu/p/14070995.html
Copyright © 2011-2022 走看看