Android Property动画——ValueAnimation使用(一)

It’s not about how badly you want something. It’s about what you are capable of!
光有志向是不够的,重要的是你的能力。 —《疯狂动物城》

1. 概述

前述的所有动画效果叫做Tween Animation(补间动画)。而在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animation(属性动画)

  • View Animation包括Tween Animation(补间动画) 和 Frame Animation(逐帧动画)
  • Property Animation包括ValueAnimator 和 ObjectAnimator

直观上有如下三点不同:

  • **引入时间不同:**View Animation是API Level 1就引入的。Property Animation是API Level 11引入的,即Android 3.0才开始有Property Animation相关的API
  • **所在包名不同:**View Animation在包android.view.animation中。而Property Animation API在包 android.animation中
  • 动画类的命名不同:View Animation中动画类取名都叫XXXXAnimation,而在Property Animator中动画类的取名则叫XXXXAnimator

1.1 引入Property Animator原因

  • Property Animator 能实现补间动画无法实现的功能
  • View Animation仅能对指定的控件做动画,而Property Animator是通过改变控件某一属性来做动画
  • 补间动画虽能对控件做动画,但并没有改变控件的内部属性值,而Property Animator则恰恰相反,通过改变控件内部的属性值来达到动画效果。

1.2 实例说明

  • 布局(main.xml)

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent">
     
        <Button
                android:id="@+id/btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="start anim"
                />
        <TextView
                android:id="@+id/tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:background="#ffff00"
                android:text="Hello qijian"/>
    </LinearLayout>
    
  • Java代码操作

    public class MyActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
     
            final TextView tv  = (TextView) findViewById(R.id.tv);
            Button btn  = (Button)findViewById(R.id.btn);
     
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    final TranslateAnimation animation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 400,
                            Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 400);
                    animation.setFillAfter(true);
                    animation.setDuration(1000);
                    tv.startAnimation(animation);
                }
            });
     
     
            tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MyActivity.this,"clicked me",Toast.LENGTH_SHORT).show();
                }
            });
     
        }
    }
    

2. ValueAnimation

2.1 ValueAnimation 简单使用

关于ValueAnimation的使用主要分两步走:

  • 创建ValueAnimator实例:

    ValueAnimator animator = ValueAnimator.ofInt(0,400);
    animator.setDuration(1000);
    animator.start();
    
  • 添加监听

    ValueAnimator animator = ValueAnimator.ofInt(0,400);
    animator.setDuration(1000);
    
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
          int curValue = (int)animation.getAnimatedValue();
          Log.d("hello","curValue:"+curValue);
      }
    });
    animator.start();
    

    从上述两步可以看出:ValueAnimator负责对数字区间做动画运算,然后对运算过程做监听,最后自己对控件做动画操作。

这里用ValueAnimator来完成前述的实例:

详细代码参见Github

2.2 ofInt与ofFloat

二者函数声明如下:

public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofFloat(float... values)

参数类型都是可变参数长参数,可以传入任何数量的值。传进去的值列表,表示动画的变化范围:比如ofInt(2,90,45)就表示从数值2变化到数字45;数字越多,变化越复杂。二者的区别是传入的数字类型不一样。
示例:

ValueAnimator animator = ValueAnimator.ofFloat(0f,400f,50f,300f);
animator.setDuration(3000);
 
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float curValueFloat = (Float)animation.getAnimatedValue();
        int curValue = curValueFloat.intValue();
        tv.layout(curValue,curValue,curValue+tv.getWidth(),curValue+tv.getHeight());
    }
});
animator.start();

我们在监听时,首先得到当前动画的值

Float curValueFloat = (Float)animation.getAnimatedValue();

通过getAnimatedValue()来获取当前运动点的值,大家可能会疑问为什么要转成Float类型,可以查看一下getAnimatedValue()声明:

Object getAnimatedValue();

它返回的类型是一个Object原始类型,那我们怎么知道我们要将它强转成什么类型呢。注意,我们在设定动画初始值时用的是ofFloat()函数,所以每个值的类型必定是Float类型,所以我们获取出来的类型也必然是Float类型的。同样,如果我们使用ofInt设定的初始值,那么通过getAnimatedValue()获取到的值就应该强转为Int类型。

2.3 监听器

在ValueAnimator中共有两个监听器:

/**
 * 监听器一:监听动画变化时的实时值
 */
public static interface AnimatorUpdateListener {
    void onAnimationUpdate(ValueAnimator animation);
}
//添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)
/**
 * 监听器二:监听动画变化时四个状态
 */
public static interface AnimatorListener {
    void onAnimationStart(Animator animation);
    void onAnimationEnd(Animator animation);
    void onAnimationCancel(Animator animation);
    void onAnimationRepeat(Animator animation);
}
//添加方法为:public void addListener(AnimatorListener listener) 

AnimatorUpdateListener就是监听动画的实时变化状态。
AnimatorListener中,主要是监听Animation的四个状态,startendcancelrepeat;当动画开始时,会调用onAnimationStart(Animator animation)方法,当动画结束时调用onAnimationEnd(Animator animation),当动画取消时,调用onAnimationCancel(Animator animation)函数,当动画重复时,会调用onAnimationRepeat(Animator animation)函数。

添加AnimatorListener的方法是addListener(Animator listener);

private ValueAnimator doAnimatorListener(){
    ValueAnimator animator = ValueAnimator.ofInt(0,400);
 
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int curValue = (int)animation.getAnimatedValue();
            tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
        }
    });
    animator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            Log.d("TAG","animation start");
        }
 
        @Override
        public void onAnimationEnd(Animator animation) {
            Log.d("TAG","animation end");
        }
 
        @Override
        public void onAnimationCancel(Animator animation) {
            Log.d("TAG","animation cancel");
        }
 
        @Override
        public void onAnimationRepeat(Animator animation) {
            Log.d("TAG","animation repeat");
        }
    });
    animator.setRepeatMode(ValueAnimator.REVERSE);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.setDuration(1000);
    animator.start();
    return animator;
}

取消监听

/**
 * 移除AnimatorUpdateListener
 */
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
 /**
  * 移除AnimatorListener
  */
void removeListener(AnimatorListener listener);	//移除指定的监听器
void removeAllListeners();	// 移除所有的监听器
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
 
    …………
    btnStart.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            repeatAnimator = doAnimatorListener();
        }
    });
 
    btnCancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            repeatAnimator.removeAllListeners();
        }
    });
}

2.4 相关函数

/**
 * 设置动画时长,单位是毫秒
 */
ValueAnimator setDuration(long duration)
/**
 * 获取ValueAnimator在运动时,当前运动点的值
 */
Object getAnimatedValue();
/**
 * 开始动画
 */
void start()
/**
 * 设置循环次数,设置为INFINITE表示无限循环
 */
void setRepeatCount(int value)
/**
 * 设置循环模式
 * value取值有RESTART,REVERSE,
 */
void setRepeatMode(int value)
/**
 * 取消动画
 */
void cancel()

/**
* 延时多久时间开始,单位是毫秒
*/
public void setStartDelay(long startDelay)

/**
 * 完全克隆一个ValueAnimator实例,包括它所有的设置以及所有对监听器代码的处理
 */
public ValueAnimator clone()

示例:

private ValueAnimator doRepeatAnim(){
    ValueAnimator animator = ValueAnimator.ofInt(0,400);
 
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int curValue = (int)animation.getAnimatedValue();
            tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
        }
    });
    animator.setDuration(1000);
    animator.setRepeatMode(ValueAnimator.REVERSE);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    return animator;
}
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
 
    …………
    btnStart.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            repeatAnimator = doRepeatAnim();
            //克隆一个新的ValueAnimator,然后开始动画
            ValueAnimator newAnimator = repeatAnimator.clone();
            newAnimator.setStartDelay(1000);
            newAnimator.start();
        }
    });
 
    btnCancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            repeatAnimator.removeAllUpdateListeners();
 
            repeatAnimator.cancel();
        }
    });
}

2.5 插值器

插值器也叫加速器,前面的很多例子都可以看到ValueAnimator animator = ValueAnimator.ofInt(0, 400);,那么0~400时怎么算出来?
插值器作用,即用来控制动画区间的值是如何计算出来的。

简单使用:

ValueAnimator animator = ValueAnimator.ofInt(0,600);
 
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int curValue = (int)animation.getAnimatedValue();
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
    }
});
animator.setDuration(1000);
animator.setInterpolator(new BounceInterpolator());
animator.start();

如果想要自定义加速器,这里以LinearInterpolator为例,查看其源码:

/**
 * An interpolator where the rate of change is constant
 */
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

LinearInterpolator继承了BaseInterpolator,而BaseInterpolator继承了Interpolator接口,Interpolator接口继承了TimeInterpolator,查看其接口:

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

这里是TimeInterpolator的代码,它里面只有一个函数float getInterpolation(float input)。

参数input:input参数是一个float类型,它取值范围是0到1,表示当前动画的进度,取0时表示动画刚开始,取1时表示动画结束,取0.5时表示动画中间的位置,其它类推

返回值:表示当前实际想要显示的进度。取值可以超过1也可以小于0,超过1表示已经超过目标值,小于0表示小于开始位置

input表示当前动画进度,返回值表示动画的数值进度,对应的数值范围由我们通过ofInt()、ofFloat()来指定,这个返回值表示当前时间所对应的数值的进度。
input参数与任何我们设定的值没关系,只与时间有关,随着时间的增长,动画的进度也自然的增加

如果需要自定义插值器,只需要实现TimeInterpolator接口即可:

public class MyInterploator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        return 1-input;
    }
}

(如果要继承BaseInterpolator接口来自定义插值器,要求API最小为 22);
这里自定义的插值器将进度反转。

ValueAnimator animator = ValueAnimator.ofInt(0,600);
 
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int curValue = (int)animation.getAnimatedValue();
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
    }
});
animator.setDuration(1000);
animator.setInterpolator(new MyInterploator());
animator.start();


从图中可见,动画的数值进度从结束位置进行到起始位置。

猜你喜欢

转载自blog.csdn.net/weixin_43499030/article/details/89257645