属性动画概述:
我理解的属性动画顾名思义就是改变对象的属性值,来达到动画效果。这期间在不停的处理这个属性值,当这个值不在被处理的时候也就是动画结束的时候。可以理解为按照某种规律不停刷新属性值的过程。 而这个规律就是插值器。整个过程用数据来抽象的就是valueanimator。objectanimator是valueanimator的子类。
其已经实现了平移,渐变,旋转等动画效果。
通过ObjectAnimator可以操作任何对象,只要这个对象的属性有get和set方法,那么就可以用属性框架来操作这个属性。如果这个对象呢没有提供get和set方法,或者get和set方法对某个属性的操作不一致,这时我们可以自己来提供get和set方法。或者用一个包装来
重新提供get和set方法。例如:
private class ViewWrapper {
//所要操作的对象
private View mTarget;
public ViewWrapper(View target) {
mTarget = target;
}
public int getWidth() {
//例如要操作width属性
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
//例如要操作width属性,这里根据业务需要操作width属性。
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
//还可以提供其他属性,根据业务需要即可。
}
总之呢 ,才用属性动画时,要操作的对象的属性需要提供get和set方法。如果在开发中遇到一个
对象的属性有get和set方法,但是没有达到预期效果,这时,我们要认真查看get和set方法是不是
对属性有明确的定义和操作。有时需要仔细来看源码确定,遇到具体的需求在说。
常见的控件的属性有:
translationX/translationY :偏移距离属性rotation,rotationX、rotaitionY:旋转,水平方向和数值方向旋转
scaleX、scaleY:X方面缩放动画,y方向缩放动画
X/Y: 对象的x,y坐标属性
alpha: 透明度属性
常用类:
ValueAnimator:ObjectAnimator extent ValueAnimator:用来操作对象属性,常用的类。
利用属性动画实现一个移动效果:
ObjectAnimator.ofFloat("操作对象","当前动画属性","当前动画属性参数","当前动画属性参数");
//X方向上平移150像素 :相对位置为当前坐标
ObjectAnimator.ofFloat(textView,"TranlationX",0f,150f).setduration(1000).start();
//Y方向上平移150像素
ObjectAnimator.ofFloat(textView,"TranlationY",0f,150f).setduration(1000).start();
//相对位置为0,0原点
ObjectAnimator.ofFloat(textView,"x",0f,150f).setduration(1000).start();
ObjectAnimator.ofFloat(textView,"y",0f,150f).setduration(1000).start();
AnimatorUpdateListenter:属性动画的监听器,动画的每一帧更新时会调用此监听。
AnimatorListenerAdapter、AnimatorListener: 动画的监听事件,包括动画结束,开始,重新开始等等。通常用AnimatorListenerAdapter方便写。
动画的事件监听:
ObjectAnimator translationX = ObjectAnimator.ofFloat(btn, "translationX",0f,200f);
ObjectAnimator translationY = ObjectAnimator.ofFloat(btn, "translationY",0f,200f);
ObjectAnimator rotation = ObjectAnimator.ofFloat(btn, "rotation",0f,360f);
translationY.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(MainActivity.this,"平移动画结束了",Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
//通常情况下,我们可以根据自己的业务需要来通过AnimatorListenerAdapter 实现监听,这么写显然更省力,代码也更少.
rotation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Toast.makeText(MainActivity.this,"旋转动画结束了",Toast.LENGTH_SHORT).show();
}
});
//当然了如果想移除监听也可以
translationY.removeListener();
translationY.removeAllListeners();
//用来控制一组动画集合的执行
PropertyValuesHolder:AnimatorSet:
执行一组动画:用 PropertyValuesHolder ObjectAnimator.ofPropertyValuesHolder
//属性动画如果不加控制的话执行起来是同时执行的。
PropertyValuesHolder rotation = PropertyValuesHolder.ofFloat("rotation",0f,360f);//旋转360°
PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX",0f,200f);//x平移200个像素单位
PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY",0f,200f);//y平移200个像素单位
ObjectAnimator.ofPropertyValuesHolder(btn,translationX,rotation,translationY).setDuration(2000).start();
//执行一组动画:AnimatorSet
ObjectAnimator translationX = ObjectAnimator.ofFloat(btn, "translationX",0f,200f);
ObjectAnimator translationY = ObjectAnimator.ofFloat(btn, "translationY",0f,200f);
ObjectAnimator rotation = ObjectAnimator.ofFloat(btn, "rotation",0f,360f);
AnimatorSet set = new AnimatorSet();
// set.playTogether(rotation,translationX,translationY);//同时执行动画。异步的
// set.playSequentially(rotation,translationX,translationY); //按照顺序依次执行动画,而不是同步执行。
//可以调整动画的执行顺序,animatorSet.play(a1).before ,after,with ,//我们可以根据自己的业务需要来通过这几个方法组合
set.play(translationX).with(translationY).before(rotation);//先让平移动画执行,再让旋转动画执行。
set.setDuration(1000).start();
TypeEvaluators: 估值计算器
自定义 估值器例子 : /**
* 抛物线
* @param view
*/
public void paowuxian(final View view)
{
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(3000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.setInterpolator(new LinearInterpolator()); //思考这里的不同。。。
// valueAnimator.setInterpolator(new BounceInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
// fraction = t / duration,t是从0到3000的变化数字,因此fraction就是整个运行时长的一部分,并且是不断随着时间增长的一部分.
//可以将fraction理解为运行时长的时间的百分比,它的范围是0-1
int xcount = 0;
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
Log.e("动画运行时长(ms):", fraction * 3000 + "--");
Log.e("动画运行fraction:", fraction + "--");
// x方向200px/s ,则y方向0.5 * 10 * t
PointF point = new PointF();
//抛物线核心计算
point.x = 200 * fraction * 3;
point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);//
//圆周运动:首先要分解圆周运动,X方向上是匀速运动
return point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
//mBlueBall.setX(point.x);
// mBlueBall.setY(point.y);
view.setX(point.x);
view.setY(point.y);
Log.i("AS:", point.x + "-" + point.y);
}
});
}
Interpolators:什么是插值器:
用来定义动画的运动轨迹。比如translationX,在x轴方向的动画,加入从0移动到200,那么这个中间怎么移动呢,是直接平移还是曲线运动,
这里就会用到插值器。
参考资料::
插值器介绍:
http://blog.csdn.net/singwhatiwanna/article/details/17639987
http://blog.csdn.net/singwhatiwanna/article/details/17841165
http://blog.csdn.net/lmj623565791/article/details/38067475
慕课网属性动画教程:
http://www.imooc.com/video/5450