安卓动画学习(属性动画)
- 我们知道,View动画是只能改变视图的显示效果,而对控件的自身属性是无法改变的
- android 在API Level 11引入了Property Animation,实现了对控件自身属性改变的属性动画
- android.animation有很多接口和实现类,通过使用这些接口和实现类,我们可以很方便的生成我们自己想要的动画效果
- 下面,我大概列举一下几个平时可能用到的接口或者类,其他的读者可在官方文档上自行观看
接口 | 说明 |
---|---|
Animator.AnimatorListener | 监听动画的四个(开始,结束,暂停,重复)状态,接口中有四个方法分别监听四个状态 |
Animator.AnimatorPauseListener | 当动画被暂停,或者动画从暂停后已恢复时调用 |
LayoutTransition.TransitionListener | 该接口用于监听转场的开始和结束事件 |
ValueAnimator.AnimatorUpdateListener | 监听动画过程中值的实时变化,每当值变化就回调此接口 |
类 | 说明 |
---|---|
ArgbEvaluator | 估值器 |
FloatEvaluator | 类似上面 |
IntEvaluator | 类似上面 |
FloatArrayEvaluator | 类似上面 |
IntArrayEvaluator | 类似上面 |
PointFEvaluator | 类似上面 |
RectEvaluator | 类似上面 |
ObjectAnimator | 动画具体操作类 |
TimeAnimator | 如上 |
ValueAnimator | 如上 |
对这些类的具体讲解
ArgbEvaluator
- 这个类下只有一个他自己的方法
Object evaluate(float fraction, Object startValue, Object endValue)
- 后两个参数设置两个颜色值,第一个参数设置渐变度,值为0.0 -- 1.0,比如我们设置0.5的话,这个方法的返回值就是后面两个颜色值的中间值,我们将之转换成int类型,得到的就是该渐变度下这两个颜色参数之间的那个值,额 还是来代码 吧
ArgbEvaluator argbEvaluator = new ArgbEvaluator();
Button button = new Button(this);
for(int i = 0;i < 10;i++){
try {
Thread.sleep(100);
int c = (int) argbEvaluator.evaluate((float) i/10, 0x00f0f0, 0xffffff);
button.setBackgroundColor(c);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
- 这里只是简单说明一下效果,不保证代码的健壮性
- 我在一个循环里面每次调用这个方法得到一个进度的颜色值,然后将其设置给button,这样,他的效果就是在一秒内,颜色从00f0f0变到ffffff;
- 底下其他的几个估值器都是一样的,就不再细说
ValueAnimator
- 这个的用法主要是构建一个变化的值区间,然后通过监听来改变我们相应的控件属性来达到动画的目的
- 直接看一下大概用法吧
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();
- 应该很容易理解吧,设置变化区间,设置变化时长,然后设置值变回调接口,值变回调时来实现我们自己的控件属性改变达到动画的效果
- 类似的方法还有
ofInt(int... values)
ofArgb(int... values)
ofObject(TypeEvaluator evaluator, Object... values)
ofPropertyValuesHolder(PropertyValuesHolder... values)
- 看一下其他常用的方法
/**
* 设置动画时长,单位是毫秒
*/
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()
- 为我们的值变化添加监听器方法
/**
* 监听器一:监听动画变化时的实时值
*/
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
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/**
* 移除AnimatorListener
*/
void removeListener(AnimatorListener listener);
void removeAllListeners();
- 还是来看一下代码和效果吧
propertyBt = findViewById(R.id.main_PropertyBt);
final ValueAnimator animator = ValueAnimator.ofFloat(0,400,100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float i = (float) animation.getAnimatedValue();
int it = i.intValue();
propertyBt.layout(it,it,it+propertyBt.getWidth(),it+propertyBt.getHeight());
}
});
animator.setDuration(3000);
propertyBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animator.start();
}
});
没啥难度,看下效果
额,视频转码有点问题,不过效果是可以看出来了,结合代码我们也能很容易的理解,所谓属性动画,其实就是给我们包装了一个工具类而已,将我们需要的数字间距或者颜色间距之类的给我们分隔好,然后控件的属性我们自己去改变
嗯,到这里我们是不是有点抓住什么了呢,属性动画的实现是返回给我们一系列的值供我们处理,而我们在前面刚看到的估值器是返回给我们指定进度的值,那么这两者之间?
对,没错,属性动画内部的处理器就是用这个估值器这个类干的,之所以有不同的类型,所谓术业有专攻嘛,毕竟颜色代码的估值可不是跟整型估值一样 安卓还为我们提供了自定义估值器的接口
看一下官方给我们的解释
TypeEvaluator <T> 用于该功能的接口。 setEvaluator(TypeEvaluator)
- 是不是瞬间明白了,我们可以写一个自己的估值器来随便自定义自己想要的效果,比如
public class MyEvaluator implements TypeEvaluator<Integer> {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int) (endValue - fraction * (endValue - startInt));
}
}
- 然后再用set方法设置进去就好咯,这里就不再说明
- 同时,我们还可以设置动画效果的快慢,插值器,关于插值器的介绍在上篇博客有写到,其实很好理解,官方为我们提供的几个插值器就是大概改变了一下我们的取值区间值变化的快慢
- 比如正常效果,值是匀速变化的,使用插值器之后,我们就可以实现区间值先变慢,在变快之类的效果,当然我们还可以实现官方给我们提供的接口,实现我们自己的插值器
public interface TimeInterpolator {
float getInterpolation(float input);
}
- 一般推荐实现这个接口,这个input参数表示当前的进度,取值为0-1;
- 如果我们想实现加速效果,就可以这么做
- 在0-0.5区间,我们让返回的值变成2倍,在0.5-1区间,让返回的值变成二分之一,这样就实现了先加速后减速的效果,具体更炫的就看个人发挥了,这里我大概给个例子看一下
- 额 ,比较尴尬,还是看看代码吧
animator.setInterpolator(new TimeInterpolator() {
@Override
public float getInterpolation(float input) {
float i;
if(input > 0.5){
i = (float) (0.01 + (1 - 0.01) * ((input - 0.5) / (1 - 0.01)));
}else {
i = (float) (0 + (0.01 - 0) * ((input - 0) / (0.01)));
}
return i;
}
});
animator.setEvaluator(new TypeEvaluator<Integer>() {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + (fraction) * (endValue - startInt));
}
});
- 想自己写个加速的插值器来着,可是百思不得其解,
- 先看他们俩的代码吧
- 插值器的接口方法是获取当前进度,我们改变他获取的当前进度就可以改变快慢了
- 而估值器是拿到当前的进度和初值以及终值,返回当前进度位置的值
- 我的想法是,让真实进度在0-0.5时,我返回的进度是0-0.25,在0.5-1时,我返回的进度是0.25-1;这样就实现了前半段减速,后半段加速的效果,可是不知道怎么,没有实现,逻辑比较强的小伙伴可以在这里多研究研究,写一下自己的插值器
- 接着往下看
ValueAnimator随我心
- 除了传值ofInt,ofFloat之外,他还为我们提供了一个方法
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values);
- 可以看出这个方法有些特殊,他需要我们自己传进去一个估值器,可是想想,不就是这样的吗
- 你想随意传东西,好啊,那你传呗,你传的你自己去处理,我可不管,系统可不知道你会传什么东西,所以将这个处理权交给了你
- 本来想着在这里贴段代码,可是写了一下,好像也没啥贴的,看别人的是直接操作View,可是,想一下ValueAnimator的原理就明白,ValueAnimator做的只是简单的帮我们处理值,无论是改变什么属性,这些都是需要我们自己去做的,所以说,具体想怎么写还是具体看项目需求吧