属性动画ValueAnimator在自定义View中的使用 属性动画核心类
来源:互联网 发布:岩泉一数据 编辑:程序博客网 时间:2024/06/05 05:23
http://mafei.site/2016/07/17/android-valueanimator/
功能强大的属性动画(property animation)
最近在学习有关自定义View
的内容,在Github上看到好多开源的View
控件,如果涉及动画,基本上都使用的是属性动画,学习到了使用属性动画自定义View
的方便和强大。所以想记录一下在自定义View
时,使用属性动画的几个方面。
属性动画的强大之处在于可以对任意对象的任意属性增加动画效果,并且可以自定义值的类型和变化过程(
TypeEvaluator
)和过渡速度(Interpolator
)。
这篇文章先来看看ValueAnimator
的使用方法。
ValueAnimator
ValueAnimator
是属性动画的核心类,最常用的ObjectAnimator
就是它的子类。此类只是以特定的方式(可以自定义)对值进行不断的修改,已达到某种想要的过渡效果。此类提供设置播放次数、动画间隔、重复模式、开始动画以及设置动画监听器的方法。
看一个最简单的例子吧。
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1.0f);animator.setDuration(3000);animator.setInterpolator(new LinearInterpolator());animator.start();
以上代码先使用ofFloat
方法传递0,1参数初始化了一个ValueAnimator
对象,接着设置动画播放的时间,设置变化速率为系统提供的线性变化,最后启动动画。
达到的效果是,在3000毫秒内从0线性增加到1。
可以添加监听器获取具体改变的值。
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {float value = (Float)animation.getAnimatedValue();Log.d(TAG, value);}});animator.start();
结果打印从0到1线性变化的值,并且耗时3000毫秒。如果我们不设置Interpolator
,会调用默认的Interpolator
,先加速增加后减速增加。
怎样使用ValueAnimator自定义View动画?
当然,上面的代码只是对数字的变化的操作,并没有涉及到动画效果。接下来我们通过在动画开始前(start方法)设置监听器来让自定义View
做出相应的动画。
如果想要做出如下图所示的效果,使用ValueAnimator
就特别简单。
这是效果图:
横向移动gif
由于效果是一个小球从左边移动一段距离后,重复执行。变化的值只有小球圆心的X轴坐标。所以可以利用ValueAnimator
产生从开始位置到结束位置的一系列中间值,设置小球移动的动画。
直接上代码:
onDraw方法:根据XPoint
(x轴坐标)绘制圆形。
protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(XPoint, heightSpecSize / 2, 30, mPaint);}
对外提供开始动画的start方法:创建ValueAnimator
对象,以及各种属性,添加监听器把每次改变的值赋值给xPoint
,并且通知view
重绘,最后开始动画。
public void start() {final ValueAnimator animator = ValueAnimator.ofFloat(60, 600);animator.setDuration(2000);animator.setRepeatCount(ValueAnimator.INFINITE);animator.setRepeatMode(ValueAnimator.RESTART);animator.setInterpolator(new LinearInterpolator());animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {XPoint = (Float)animation.getAnimatedValue();invalidate();}});animator.start();}
以上代码首先创建一个从60变化到600的ValueAnimator
对象,接着设置动画时间、重播方式、重播次数和速度变化情况,最后增加监听器,每次获取变化的值再赋值给xPoint
,接着很重要的一点,调用invalidate()
方法通知View
重绘,即值每次改变都需要View
重绘。
这样就很方便的根据float
值的改变,给view
增加了动画的效果。
TypeEvaluator
前面的例子,创建ValueAnimator
的时候,都是使用的ValueAnimator.ofFloat(float, float)
方法,这个方法传递的参数为可变参数。其实创建ValueAnimator
也可以使用ofInt
等方法,还有一个很重要的方法:ValueAnimator.ofObject(TypeEvaluator, Object...)
,此方法和其他方法不同之处在于第一个参数TypeEvaluator
,此处需要使用系统已经实现好的或自定义子类,用于设定自定义类型。
在使用ofInt
或ofFloat
方法时,其实是使用了FloatEvaluator
、FloatArrayEvaluator
、IntEvaluator
、IntArrayEvaluator
这些系统已经实现好了的TypeEvaluator
。我们使用这些方法创建ValueAnimator
时就不必自定义类来继承TypeEvaluator
。
假如现在需要这个圆形斜着移动,使用ValueAnimator
该怎样实现?当然很很多简单的实现方法,比如Path
路径的使用,这里为了演示自定义TypeEvaluator
,使用自定义TypeEvaluator
的方式来实现。
这是效果图:
斜着移动gif
自定义类PointEvaluator
实现TypeEvaluator
接口。
class PointEvaluator implements TypeEvaluator{public Object evaluate(float fraction, Object startValue, Object endValue) {Point startPoint = (Point) startValue;Point endPoint = (Point) endValue;int x = (int) (startPoint.x + fraction * (endPoint.x - startPoint.x));int y = (int) (startPoint.y + fraction * (endPoint.y - startPoint.y));return new Point(x, y);}}
这里需要实现evaluate
方法,根据动画完成的百分比返回对应的值。其中fraction
参数和动画时间有关,代表动画执行的完成程度,比如动画总时间为3000毫秒,现在执行了1000毫秒,那么此刻传递进来的fraction
参数值为三分之一。
在onDraw
方法中依然还是简单的绘制一个圆形,此圆的圆心坐标是成员变量mPoint
的x
,y
值。
protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(mPoint.x, mPoint.y, 30, mPaint);}
最后提供start
方法开始动画。
public void start() {final ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(),new Point(30, 30), new Point(600, 600));animator.setDuration(2000);animator.setRepeatCount(ValueAnimator.INFINITE);animator.setRepeatMode(ValueAnimator.REVERSE);animator.setInterpolator(new LinearInterpolator());animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {mPoint = (Point)animation.getAnimatedValue();invalidate();}});animator.start();}
和上边的代码类似,只是ValueAnimotor
操作的值从float
改变成了Point
(可以自定义类型),不再做过多的解释了。
这个例子,我们可以知道ValueAnimotor
操作的值的类型是任意的,可以由我们来自定义,只要自定义类实现TypeEvaluator
,并且实现此接口的唯一一个方法evaluate
即可。
TimeInterpolator
TimeInterpolator
表示动画的速率,上边代码中我们就设置了动画速率,只不过使用的是API中已经实现好了的LinearInterpolator
。
查询API知道TimeInterpolator
接口有很多已知的实现类,比如AccelerateDecelerateInterpolator
表示先加速后减速,AccelerateInterpolator
表示一直加速,DecelerateInterpolator
表示一直加速等。BounceInterpolator
可以模拟物理规律,实现反弹的效果
如果不设置setInterpolator
,那么默认使用AccelerateDecelerateInterpolator
。
在自定义TimeInterpolator
之前,我们先看看API中提供的实现的例子:LinearInterpolator
,AccelerateInterpolator
。
TimeInterpolator
接口,只有一个方法:getInterpolation(float input)
,此方法接收一个float
类型的input
值,此值的变化范围为0~1,并且根据动画运行的时间,均匀增加,和TypeEvaluator
接口方法中的参数fraction
很像,fraction
也是根据动画运行的时间,均匀增加。
注意:getInterpolation函数的返回值传递给了fraction
LinearInterpolator
源码:
public class LinearInterpolator extends BaseInterpolatorimplements NativeInterpolatorFactory {public LinearInterpolator() {}public LinearInterpolator(Context context, AttributeSet attrs) {}public float getInterpolation(float input) {return input;}/** @hide */public long createNativeInterpolator() {return NativeInterpolatorFactoryHelper.createLinearInterpolator();}}
从源码中,可以看到getInterpolation
的逻辑简单到不能再简单,直接返回input
,因为input
本身表示的就是均匀增加的。
AccelerateInterpolator
源码:
public float getInterpolation(float input) {if (mFactor == 1.0f) {return input * input;} else {return (float)Math.pow(input, mDoubleFactor);}}
构造函数接收一个mFactor
表示加速的倍数,接收1.0f以上的数,mDoubleFactor = 2 * mFactor
。
在getInterpolation
方法中,判断mFactor
如果等于1.0f,直接返回input * input
(默认,二次函数增长),否则返回input
的mDoubleFactor
次方(mDoubleFactor次函数增长)。
看来要想实现一个自定义的TimeInterpolator
,得要有一些必要的数学修养了。没办法,数学没有那么好,只能实现一个简单的TimeInterpolator
,演示自定义TimeInterpolator
的步骤。
注意:最好让getInterpolation方法返回的值在0~1之间,以便在使用fraction参数时意思明确
下面我们实现一个以10给底数的负指数函数减速的例子:
class LgDecelerateInterpolator implements TimeInterpolator {private float background;public LgDecelerateInterpolator() {background = 10;}public float getInterpolation(float input) {return (1 - (float) Math.pow(background, -input));}}
然后在设置animator.setInterpolator(new LgDecelerateInterpolator());
,就可以使用了。
成员变量background
表示底数,在构造方法中初始化为10,因为是减速,所以用到了负指数,得到的值从1变化到0,所以再用1减去这个结果值,就得到了最终的结果。
AnimatorSet
AnimatorSet
表示动画的集合,可以把几个动画一起播放,或按次序播放。提供paly
、with
、after
等方法。
接下来,把以上用到的全部结合起来,播放一个动画的效果:圆形从View
的左上角移动到右下角,伴随着颜色的变化,移动速度和颜色变化的速率都由上面自定义的LgDecelerateInterpolator
实现。
这是效果图:
斜着指数减速移动伴随颜色指数渐变gif
这是完整的代码:
public class MyView extends View {private Paint mPaint;private Point mPoint;private int mColor;public MyView(Context context, AttributeSet attrs) {super(context, attrs);initPaint();}public MyView(Context context) {super(context);initPaint();}private void initPaint() {mPaint = new Paint();mPaint.setColor(0xFFF00000);mPaint.setAntiAlias(true); // 抗锯齿}protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(mPoint.x, mPoint.y, 60, mPaint);}public void start() {final ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(),new Point(60, 60), new Point(990, 1050));animator.setRepeatCount(ValueAnimator.INFINITE);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {mPoint = (Point) animation.getAnimatedValue();invalidate();}});final ValueAnimator animator1 = ValueAnimator.ofArgb(0xFFF00000,0xFFFFFF00);animator1.setRepeatCount(ValueAnimator.INFINITE);animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {mColor = (int) animation.getAnimatedValue();mPaint.setColor(mColor);}});AnimatorSet animationSet = new AnimatorSet();animationSet.setDuration(3000);animationSet.setInterpolator(new LgDecelerateInterpolator());animationSet.play(animator).with(animator1);animationSet.start();}class PointEvaluator implements TypeEvaluator {public Object evaluate(float fraction, Object startValue, Object endValue) {Point startPoint = (Point) startValue;Point endPoint = (Point) endValue;int x = (int) (startPoint.x + fraction * (endPoint.x - startPoint.x));int y = (int) (startPoint.y + fraction * (endPoint.y - startPoint.y));return new Point(x, y);}}class LgDecelerateInterpolator implements TimeInterpolator {private float background;public LgDecelerateInterpolator() {background = 10;}public float getInterpolation(float input) {return (1 - (float) Math.pow(background, -input));}}}
start
方法中创建了两个ValueAnimator
,第一个使用.ofObject
方法,通过传递自定义的PointEvaluator
,第二个使用API已经实现的ofArgb
使颜色值变化的动画属性,都添加监听器以实现对成员变量的修改,重绘View
,最后创建AnimatorSet
对两个动画进行叠加,在播放移动动画的同时播放颜色渐变的动画。
- 属性动画ValueAnimator在自定义View中的使用 属性动画核心类
- 属性动画ValueAnimator在自定义View中的使用
- 自定义View和属性动画ValueAnimator实现圆点指示器
- 属性动画在自定义控件中的使用
- Android自定义控件:动画类(五)----属性动画ValueAnimator基本使用
- Android 2.x自定义属性动画ValueAnimator
- android 属性动画(ValueAnimator)
- 属性动画之ValueAnimator
- 属性动画之ValueAnimator
- 属性动画二--ValueAnimator
- ValueAnimator属性动画
- Android属性动画 ValueAnimator
- android 动画 属性动画 ValueAnimator
- 属性动画在Android自定义View中的应用场景
- 属性动画ValueAnimator和ObjectAnimator的使用
- Android属性动画之ValueAnimator使用
- ValueAnimator的初步使用(动画属性)
- 三、ValueAnimator属性动画的基本使用
- CDH中服务的配置及启动
- String&&StringBuffer&&StringBuilder深层次解析
- POJ 1703 Find them, Catch them 种群并查集
- RecycleView的使用
- Linux sed命令详解
- 属性动画ValueAnimator在自定义View中的使用 属性动画核心类
- 状压DP hunter
- POJ2492 A Bug's Life 种群并查集
- JVM堆溢出实例
- poj 1996 The Highest Profits(数学多项式)
- Java Se----数组
- JVM简介
- Android Toolbar设置向上箭头,标题等
- sdut oj2054 数据结构实验之链表九:双向链表