前言
之前我们把视图动画(也就是View动画)分析的差不多了,当然帧动画我们没有讲解,其实帧动画比较简单,就是通过顺序播放一系列的图像从而产生动画效果,可以简单理解为图片的切换。和我们小时候玩的翻书让物体动起来是一个道理。它使用起来也比较简单。所以我们就不单独拿出来讲解。到后面我们会用到时再去简单讲解。这篇我们继续来学习动画之属性动画(Property Animator)。
介绍
我们在第一篇文章的时候就提到过动画的分类:视图动画,属性动画。当时我们讲解了2者的区别。但是我们没有分析具体2者的不同与使用场景。并且已经有了View动画,为何有加入属性动画呢?
-
Property Animator能实现补间动画无法实现的功能 ;
- 比如我们想将一个控件的宽度增加,用动画来这么做呢?有人会觉得直接用缩放(scaleX)来做,但是做出来的效果却是将控件宽度拉长而不是增加。不管是从视觉上还是理解上都不是我们想要的效果。后期我们会做实验来试一下。再者我们想改变一个控件颜色用View动画也是无法做到的,因为View动画只能对派生自View的控件实例起作用;。但是属性动画却可以对任意"对象"起作用,甚至是没有对象。它可以达到的效果为:在一个时间间隔内,完成对象从一个属性值到里一个属性值的改变,所以,属性动画几乎无所不能。名字中可以看出属性动画,应该是作用于控件属性的!正因为属性动画能够只针对控件的某一个属性来做动画,所以也就造就了他能单独改变控件的某一个属性的值!比如颜色!这就是Property Animator能实现补间动画无法实现的功能的最重要原因。
-
View Animation仅能对指定的控件做动画,而Property Animator是通过改变控件某一属性值来做动画的。
- View动画之所以叫视图动画,因为它做动画是对控件的视图,影像做动画,并没有改变控件的属性。所以当我们用视图做动画完成后造成点击事件与setVisibility(View.GONE)失效。那么我们就可以得出结论:补间动画虽能对控件做动画,但并没有改变控件内部的属性值。而Property Animator则是恰恰相反,Property Animator是通过改变控件内部的属性值来达到动画效果的。
那事实到底是不是这样的呢?下面我们就用实际的例子来证实一下。那我实际运行下:
可以看到,当我们没有做动画的时候隐藏控件与点击事件都是有效的。但是当我们在动画完成后,点击控件却没有响应点击事件,同时隐藏也无效。但是点击控件初始位置却可以响应点击事件。这就说明View动画虽能对控件做动画,但并没有改变控件内部的属性值。
提示: 如果想隐藏的话可以使用view.clearAnimation()清楚View动画。
ValueAnimator
ValueAnimator本身不作用与任何对象,也就是说直接使用时没有任何动画效果的。它可以对一个值做动画。然后我们可以监听其动画的过程,在动画的过程中修改我们对象的属性值,这样也就相当于对我们的对象做了动画。下面我们就来使用下。
-
常用方法
在使用之前,我们先来看下ValueAnimator常用的方法有哪些:
创建对象
一般情况我们会调用ValueAnimator的静态方法创建对象。
参数类型都是可变参数长参数,所以我们可以传入任何数量的值;传进去的值列表,就表示动画时的变化范围;比如ofInt(2,90,45)就表示从数值2变化到数字90再变化到数字45;所以我们传进去的数字越多,动画变化就越复杂。从参数类型也可以看出ofInt与ofFloat的唯一区别就是传入的数字类型不一样,ofInt需要传入Int类型的参数,而ofFloat则表示需要传入Float类型的参数。
public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofFloat(float... values)
常用方法
·
/**
* 延时多久时间开始,单位是毫秒
*/
public void setStartDelay(long startDelay)
/**
* 设置动画时长,单位是毫秒
*/
ValueAnimator setDuration(long duration)
/**
* 获取ValueAnimator在运动时,当前运动点的值
*/
Object getAnimatedValue();
/**
* 开始动画
*/
void start()
/**
* 设置循环次数,设置为INFINITE表示无限循环
*/
void setRepeatCount(int value)
/**
* 设置循环模式
* value取值有RESTART,REVERSE,
*/
void setRepeatMode(int value)
/**
* 取消动画
*/
void cancel()
/**
* 暂画动画
*/
void pause()
/**
* 继续动画
*/
void resume()
这里面方法都比较简单,这里我们介绍下
Object getAnimatedValue();
这个方法的含义是:获取ValueAnimator在运动时,当前运动点的值,返回Object。如何理解呢?我们知道在创建对象的时候我们有两个方法一个是传入int一个float,这里就是获取相应某一时间当前运动点的值。传入的是int返回就是int,返回float就是float。为了更方便理解下面我们实际使用下,使用方法如下:
- 创建ValueAnimator对象
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 400);
valueAnimator.setDuration(2000);
- 添加监听
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int) animation.getAnimatedValue();
Log.d("qijian", "curValue:" + curValue);
mTextView.layout(curValue, curValue, curValue + mTextView.getWidth(), curValue + mTextView.getHeight());
}
});
- 开启动画
valueAnimator.start();
这里我们利用ofInt创建对象,传入(0,400)这里的含义是利用ValueAnimator动画创建一个从0-400一个改变的值,然后设置其数值变换的监听,在监听内部获取到从动画开始到结束时间内变换的数值,然后将在变化中重新设置textview的位置,使textview从屏幕(0,0)点运动到(400,400)点。
valueAnimator.addUpdateListener() 监听数值变换的监听。这里意思就是动画时长为2s,在2s内数值变换0-400,每次变换都会调用这个监听在这个监听里面我们可以获取到具体变换的数值。
int curValue = (int) animation.getAnimatedValue(); 这个方法就是上面我们讲到的,获取当前动画运动点的值
mTextView.layout()这个方法是设置textView的布局。里面参数分别对应控件所在矩形的左上右下四个点。我们这里动态设置变换的数值从而达到动画的效果。
下面我们来看下效果:
监听:
12-24 02:26:21.690 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:0
12-24 02:26:21.709 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:0
12-24 02:26:21.729 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:0
12-24 02:26:21.749 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:1
12-24 02:26:21.771 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:1
12-24 02:26:21.797 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:3
12-24 02:26:21.821 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:4
12-24 02:26:21.845 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:6
12-24 02:26:21.863 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:8
12-24 02:26:21.889 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:11
省略中间部分.....
12-24 02:26:23.543 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:395
12-24 02:26:23.560 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:396
12-24 02:26:23.581 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:397
12-24 02:26:23.597 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:398
12-24 02:26:23.616 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:398
12-24 02:26:23.623 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:399
12-24 02:26:23.642 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:399
12-24 02:26:23.656 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:399
12-24 02:26:23.674 4880-4880/com.example.ggxiaozhi.customview2 D/TAG: curValue:400
可以看到在监听中获取到的值确实是从0到400变换。也实现了我们动画的效果。
监听
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)
/**
* 监听器三:监听动画暂停与重新开始
*/
public static interface AnimatorPauseListener {
void onAnimationPause(Animator animation);
void onAnimationResume(Animator animation);
}
//添加方法为:public void addPasueListener(AnimatorPauseListener listener)
监听器一:AnimatorUpdateListener就是监听动画的实时变化状态,在onAnimationUpdate(ValueAnimator animation)中的animation表示当前状态动画的实例。
监听器二:主要是监听Animation的四个状态,start、end、cancel、repeat;当动画开始时,会调用onAnimationStart(Animator animation)方法,当动画结束时调用onAnimationEnd(Animator animation),当动画取消时,调用onAnimationCancel(Animator animation)函数,当动画重复时,会调用onAnimationRepeat(Animator animation)函数。
监听器三:监听动画暂停与重新开始
- 取消监听器
/**
* 移除AnimatorUpdateListener
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/**
* 移除AnimatorListener
*/
void removeListener(AnimatorListener listener);
void removeAllListeners();
/**
* 移除AnimatorPauseListener
*/
valueAnimator.removePauseListener(AnimatorPauseListener listener);
针对AnimatorUpdateListener和AnimatorListener,每个监听器都有两个方法来移除;我们就以移除AnimatorListener来简单讲一下,removeListener(AnimatorListener listener)用于在animator中移除指定的监听器,而removeAllListeners()用于移除animator中所有的AnimatorListener监听器;
下面我们测试一下,效果:
这里方法对应关系start()->cancel() pause() ->resume()
从打印中我们可以看到开始和继续的区别 结束和暂停的区别。当我移除 AnimatorListener时状态就不在打印但是动画在运动,移除AnimatorUpdateListener动画会停止。因为我们在AnimatorUpdateListener监听中获取到的值,所以移除监听后我们就获取不到改变的值了,所以动画也就停止了。
- 更多函数:
/**
* 完全克隆一个ValueAnimator实例,包括它所有的设置以及所有对监听器代码的处理
*/
public ValueAnimator clone()
克隆就是完全一样!注意是完全一样!就是复制出来一个完全一样的新的ValueAnimator实例出来。对原来的那个ValueAnimator是怎么处理的,在这个新的实例中也是全部一样的。
注意: 克隆得到的新对象newAnimator与之前对象是2个不同的对象。对newAnimator进行的所有操作不会影响到valueAnimator对象。
使用:
ValueAnimator newAnimator = valueAnimator.clone();
其他更多函数请查阅文档
结语
到这里ValueAnimator的基本使用与View动画的区别就差不多了。
感谢
站在巨人的肩膀上可以让我们看的更远。
Android自定义控件三部曲文章