转载请注意:http://blog.csdn.net/wjzj000/article/details/54384918
本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)
写在前边
动画系列好久之前写了一篇关于View动画的简单使用:
http://blog.csdn.net/wjzj000/article/details/53524646
今天就把没填完的属性动画的坑填上。关于属性动画的使用仅仅是提一提。主要来梳理插值器和估值器…
简单的使用
单方面动画
- 翻转动画代码:
/**
* 我们通过ofFloat的静态方法(当然也有其他的静态方法)
* 第一个参数是动画作用的View
* 第二个是动画方式,比如这里写的“rotationX”:以X为中心旋转
* 接下来的参数是动画进行的属性值
* 这里的意思是0度到360度,也可以继续往后写,那么就会继续执行对应的动画
*/
valueAnimator =ObjectAnimator.ofFloat(ivImage, "rotationX", 0.0f, 360.0f);
valueAnimator.setDuration(1000);
valueAnimator.start();
- 平移动画代码:
valueAnimator =ObjectAnimator.ofFloat(ivImage, "translationX", 0.0f, 360.0f,0.0f);
valueAnimator.setDuration(2000);
valueAnimator.start();
- 透明度动画代码:
valueAnimator =ObjectAnimator.ofFloat(ivImage, "alpha", 0.0f, 1.0f,0.0f,1.0f);
valueAnimator.setDuration(2000);
valueAnimator.start();
- 尺寸动画代码:
valueAnimator =ObjectAnimator.ofFloat(ivImage, "scaleX", 1.0f, 1.5f,1.0f);
valueAnimator.setDuration(2000);
valueAnimator.start();
- 重复模式代码:
//动画额外重复次数
valueAnimator.setRepeatCount(2);
/**
* repeatMode 动画重复类型(至少要有setRepeatCount())
* ValueAnimator.RESTART:动画将从每个新循环的开始位置重新的开始
* ValueAnimator.REVERSE:表示动画在每次重复的时候将反转方向重新开始
* 如果不好理解可以下下面的效果
*/
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
- ValueAnimator.RESTART的效果:
- ValueAnimator.REVERSE:
综合动画
- 代码如下:
animatorSet=new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(ivImage, "scaleX", 1.0f, 1.5f,1.0f),
ObjectAnimator.ofFloat(ivImage, "alpha", 0.0f, 1.0f,0.0f,1.0f),
ObjectAnimator.ofFloat(ivImage, "translationX", 0.0f, 360.0f,0.0f),
ObjectAnimator.ofFloat(ivImage, "rotationX", 0.0f, 360.0f)
);
animatorSet.setDuration(1500);
animatorSet.start();
监听+动画分析
- 添加监听:
valueAnimator =ObjectAnimator.ofFloat(1.0f, 1.5f,1.0f);
valueAnimator.setDuration(1000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//动画每一帧的变化都会回调此方法
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value= (float) animation.getAnimatedValue();
ivImage.setScaleX(value);
}
});
注意这里的用法:
这里我们仅仅是在ofFloat中传入了想要变化的数值。其余的并没有写。(接近尾声的地方有关于此内容的梳理)
那这样的话我们会拿到什么?我们可以得到:这段时间内我们传入的值随时间的变化的值。
也就是我们在监听回调中animation.getAnimatedValue()得到的值,简单来说就是一个匀速变化的值。
ivImage.setScaleX(value);
同理我们也可以设置View的其他值…
贴一些官方的文档:
- Animator.AnimatorListener
- onAnimationStart() - 动画启动时调用。
- onAnimationEnd() - 当动画结束时调用。
- onAnimationRepeat() - 当动画重演调用。
- onAnimationCancel()-当动画被取消调用。
- ValueAnimator.AnimatorUpdateListener
- onAnimationUpdate()-称为动画的每一帧上。
- 听此事件使用所产生的计算值ValueAnimator的动画中。要使用该值,查询ValueAnimator传递到事件对象来获取与当前动画值getAnimatedValue()的方法。实现这个监听器,如果你使用的是必需的ValueAnimator。
- 根据什么属性或对象的动画,你可能需要调用 invalidate()一个视图强制屏幕的该区域的新的动画值重绘自身。例如,动画效果可绘制对象的颜色属性只造成对屏幕的更新时,该对象重绘自己。All of the property setters on View如setAlpha()和 setTranslationX()正确无效视图,所以你不需要调用这些方法与新的值时无效视图。
进入重点想记录的
先看代码
Evaluator
这个词不知道准备的翻译是什么,个人习惯叫估值器…
先整一个简单的Demo:
valueAnimator = new ValueAnimator();
valueAnimator.setDuration(10000);
//如果不设置,默认也是线性插值器,也就是均匀变化
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setObjectValues(new PointF(0, 100));
valueAnimator.setEvaluator(new TypeEvaluator<PointF>(){
// fraction = t / duration
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue){
/**
* fraction:0-1随插值器(Interpolator)变化而变化的值
* 默认是匀速变化
* x:水平方向的速度*时间(初始设置为100);y:1/2*g*t*t(自由落体运动的距离)
* View的坐标(x,y)就是对应x,y对应速度下的距离
* PS:
*/
PointF point = new PointF();
point.x = 100 * fraction * 10;
//这里并不好给重力加速度赋值,因为正常单位是米,这里是px...所以这里就忽略吧
point.y = 0.5f * 98f * (fraction * 10) * (fraction * 10);
return point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//此处得到的就是估值器中获取的Point
PointF point = (PointF) animation.getAnimatedValue();
ivImage.setTranslationX(point.x);
ivImage.setTranslationY(point.y);
}
});
PointF:它是个啥,说实话挺唬人…整个大写的F结尾,还挺邪乎。
说白了就是Point,一个坐标而已,内置x,y。为啥有个F…因为PointF中的x,y是浮点型的…所以Ponit中的x,y理所应当就是int型的….
Interpolator
插值器:其实上文那个Demo中有所涉及,说白了很好理解。这里简单梳理一发,一会代码奉上之后再详细走一波。
插值器和估值器可以理解是一对难兄难弟。我们在估值器的使用中,主要用的了这个值:fraction。通过fraction我们进行了一系列的计算。
fraction是一个0-1逐渐递增的浮点型值,而这个值就是由插值器计算而来。
通过源码来理解插值器
- LinearInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
//这个方法是接口TimeInterpolator中的方法。这里直接将传入的参数input直接返回出去。
//因为说它是均匀变化
public float getInterpolation(float input) {
return input;
}
//省略部分代码...
}
当我们调用ValueAnimator的start方法之后,start中进行对时间的计算,然后将当前动画执行的时间通过层层传递传入插值器的getInterpolation方法之中,间接的赋值给了估值器。供估计器进行相关的计算。
借用官方的图和解释:
在整个动画的进行过程中,ValueAnimator会计算出动画执行的比例( 0和1之间),计算的方法是:基于该动画的总时间和已过去的时间。所经过的分数(fraction)表示在完成动画的时间百分比,0表示0%和1的含义100%。例如,在图1中,在t的经过分率= 10毫秒将是0.25,因为总的持续时间为t = 40毫秒。
Ps:翻译的官方文档,看完官方解释感觉啥也不懂了,很绕也不好理解。
仔细捋一捋还是可以理解的,插值器和估值器二者关注的焦点就是这个fraction,它就是动画执行多长时间比上动画总时间,就是一个比例。但是说到这,是不是感觉到不对劲了?逝世的时间比总时间,这TM是个永远是个线性值啊!所以….
在这里…我们可以重写插值器中的getInterpolation方法,来手动改变这个比较。变一个说法就是,我们用一个伪造的方法来控制时间!
- 看一段代码:
//第一个平移动画我们使用线性插值器进行均匀变化
valueAnimator0=ObjectAnimator.ofFloat(black,"translationX",0.0f,500.0f);
valueAnimator0.setInterpolator(new LinearInterpolator());
valueAnimator0.setDuration(1500);
valueAnimator0.start();
//第二个平移动画我们重写控制方法,返回时间的平方
valueAnimator=ObjectAnimator.ofFloat(red,"translationX",0.0f,500.0f);
valueAnimator.setInterpolator(new TimeInterpolator() {
@Override
public float getInterpolation(float input) {
//由上文我们知道这里的input是0-1的值,因此我们返回平方,其效果会先比线性快,然后慢下来。
return input*input;
}
});
valueAnimator.setDuration(1500);
valueAnimator.start();
- 疗效好不好,看效果…
二者都是同时到达终点,但是我们可以很明显看出黑块大部分时间都处于领先位置,也就是我们设置了平方的原因。
在今天写动画的时候,其实碰到了小小的问题,有必要在接近尾声的地方记录一下。
ObjectAnimator和ValueAnimator
让我们先看代码上的不同
//很明显我们可以看出ObjectAnimator继承ValueAnimator
public final class ObjectAnimator extends ValueAnimator
public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {
二者存在了不少的不同之处:
- ValueAnimator:
public static ValueAnimator ofFloat(float... values) {
ValueAnimator anim = new ValueAnimator();
anim.setFloatValues(values);
return anim;
}
我们可以看到这里的操作方法中传递的参数,都不含动画作用View这个参数以及像“scaleX”这样的propertyName。
因此我们如果想使用ValueAnimtor则应该这么写:
valueAnimator=ValueAnimator.ofFloat( 0.0f,1.0f ,0.0f);
valueAnimator.setTarget(ivImage);
valueAnimator.setDuration(2000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ivImage.setAlpha(animation.getAnimatedFraction());
}
});
- ObjectAnimator:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
PS:相关源码基本都存放于我的这个开源项目之中:
https://github.com/zhiaixinyang/PersonalCollect
尾声
收尾的有些仓促,所以有时间还是会回过头来完善的。所以希望各位看官多多包涵,如果有不理解的地方,你TM不会多看几遍!
最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp