Android 动画之属性动画ValueAnimator和ObjectAnimator
来源:互联网 发布:mybatis 源码 编辑:程序博客网 时间:2024/06/05 03:34
简介
属性动画是API 11新加入的特性,和View动画不同,它对作用对象进行了扩展,属性动画可以对任意对象做动画,也不像View动画只支持四种简单的变化。
属性动画的默认时间是300ms,默认频率是10ms/帧
ObjectAniamtor
先看看一个简单例子的实现效果,使用ObjectAnimator,它使用起来比较简单
布局就是一个ImageView,看看实现代码
//透明度变化动画 public void alpha(View view) {// 1、通过调用ofFloat()方法创建ObjectAnimator对象,并设置目标对象、需要改变的目标属性名、初始值和结束值; ObjectAnimator mAnimatorAlpha = ObjectAnimator.ofFloat(mImageView, "alpha", 1.0f, 0.0f); //2、设置动画的持续时间、是否重复及重复次数属性; mAnimatorAlpha.setRepeatMode(Animation.REVERSE); mAnimatorAlpha.setRepeatCount(1); mAnimatorAlpha.setDuration(1000); //3、启动动画 mAnimatorAlpha.start(); } //翻转动画,翻转360度 public void flip(View view) { ObjectAnimator visibleToInVisable = ObjectAnimator.ofFloat(mImageView, "rotationX", 0.0f, 360.0f); //设置插值器 visibleToInVisable.setInterpolator(new LinearInterpolator()); visibleToInVisable.setDuration(1000); visibleToInVisable.start(); } //缩放动画 public void scale(View view) { Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scale_anim); animator.setTarget(mImageView); animator.start(); } //平移动画 public void translate(View view) { ObjectAnimator mAnimatorTranslateX = ObjectAnimator.ofFloat(mImageView, "translationX", 0.0f, screenWidth / 2); mAnimatorTranslateX.setRepeatMode(Animation.REVERSE); mAnimatorTranslateX.setRepeatCount(1); mAnimatorTranslateX.setDuration(1000); ObjectAnimator mAnimatorTranslateY = ObjectAnimator.ofFloat(mImageView, "translationY", 0.0f, screenHeight / 2); mAnimatorTranslateY.setRepeatMode(Animation.REVERSE); mAnimatorTranslateY.setRepeatCount(1); mAnimatorTranslateY.setDuration(1000); mAnimatorTranslateX.start(); mAnimatorTranslateY.start(); } //旋转动画 public void rotate(View view) { ObjectAnimator mAnimatorRotate = ObjectAnimator.ofFloat(mImageView, "rotation", 0.0f, 360.0f); mAnimatorRotate.setRepeatMode(Animation.REVERSE); mAnimatorRotate.setRepeatCount(1); mAnimatorRotate.setDuration(2000); mAnimatorRotate.start(); }
就是根据ObjectAnimator的ofFloat(Object target, String propertyName, float... values)构造得到一个ObjectAnimator,可以看到第一个参数是Object类型的,意味着我们可以传入自定义的类型,而不局限于补间动画只能用view来做,扩展性也就更好。第二个参数是动画名称,可以传递系统定义好的,比如上面的几个,也可以自己随便写,然后在属性变化的监听里改变。第三个参数就是属性值,如果只有一个的话会默认为结束值。
上面缩放动画是用xml实现的,需要在res下面建一个animator文件夹,然后创建相应的xml动画,如下
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together"> <objectAnimator android:duration="1000" android:propertyName="scaleX" android:repeatCount="0" android:repeatMode="reverse" android:startOffset="500" android:valueFrom="0.1f" android:valueTo="1.0f" android:valueType="floatType" /></set>
组合动画
现在要多个动画效果一起实现怎么办,有下面几种方式
1.PropertyValuesHolder
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0.0f, 1.0f); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f); ObjectAnimator animator1 = ObjectAnimator.ofPropertyValuesHolder(mImageView, alpha, scaleX); animator1.setDuration(1000); animator1.start();2.监听属性变化
ObjectAnimator animator = ObjectAnimator.ofFloat(mImageView, "lzy", 0.0f, 1.0f); animator.setDuration(1000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); mImageView.setAlpha(value); mImageView.setScaleX(1 - value * 0.5f); } }); animator.start();设置属性变化值在0-1之间,然后在onAnimationUpdate中监听得到,通过这个值调用view自身的方法改变。
3.AnimatorSet
AnimatorSet mAnimatorSet = new AnimatorSet(); ObjectAnimator mAnimatorSetRotateX = ObjectAnimator.ofFloat(mImageView, "rotationX", 0.0f, 360.0f); mAnimatorSetRotateX.setDuration(3000); ObjectAnimator mAnimatorSetRotateY = ObjectAnimator.ofFloat(mImageView, "rotationY", 0.0f, 360.0f); mAnimatorSetRotateY.setDuration(3000); ObjectAnimator mAnimatorScaleX = ObjectAnimator.ofFloat(mImageView, "scaleX", 1.0f, 0.2f); mAnimatorScaleX.setRepeatCount(1); mAnimatorScaleX.setRepeatMode(Animation.REVERSE); mAnimatorScaleX.setDuration(1500); ObjectAnimator mAnimatorScaleY = ObjectAnimator.ofFloat(mImageView, "scaleY", 1.0f, 0.2f); mAnimatorScaleY.setRepeatCount(1); mAnimatorScaleY.setRepeatMode(Animation.REVERSE); mAnimatorScaleY.setDuration(1500); ObjectAnimator mAnimatorScaleY2 = ObjectAnimator.ofFloat(mImageView, "scaleY", 1.0f, 0.2f); mAnimatorScaleY2.setRepeatCount(1); mAnimatorScaleY2.setRepeatMode(Animation.REVERSE); mAnimatorScaleY2.setDuration(1500); mAnimatorSet.play(mAnimatorSetRotateY) .with(mAnimatorScaleX) .with(mAnimatorScaleY) .before(mAnimatorSetRotateX).before(mAnimatorScaleY2); mAnimatorSet.start();通过animationSet来实现,它提供了一个play()方法,传入Animator返回一个Builder,这个Builder中有以下四个方法
with(Animator anim),表示同时执行
before(Animator anim),表示将现有动画插入到传入动画之前执行,也就是后执行
after(Animator anim),与before相反
after(long delay),表示延迟多久执行
在测试的时候发现不能重复传入一个动画,所以又写了一个mAnimatorScaleY2 。
AnimationSet中还有playTogether(Animator... items)表示同时执行,playSequentially(Animator... items)表示异步执行。
下面做一个让Button增加宽度的动画效果
属性动画的大致原理:属性动画要求动画作用的对象提供该属性的get和set方法,就像上面的"scaleX"属性,它具有getScaleX和setScale方法,属性动画会根据传递的初始值和结束值,去调用set的方法设置当前的值,如果没有传递初始值会调用get方法去获取初始值。
然后Button中并没有我们想要的get和set方法,所以针对这种问题官方文档给出了下面的解决方法
1.如果有权限的话,给对象加上get和set方法
2.用一个类来包装原始对象,间接为其提供get和set方法
3.采用ValueAnimator,监听动画变化过程,自己实现属性的变化
我们现在以第二种方式来实现以上效果,代码如下
mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ViewWrapper wrapper = new ViewWrapper(mButton); ObjectAnimator.ofInt(wrapper, "width", 1000).setDuration(1000).start(); } });
//用此类来封装View,间接提供get、set方法 private static class ViewWrapper { private View mView; public ViewWrapper(View view) { mView = view; } public void setWidth(int width) { mView.getLayoutParams().width = width; mView.requestLayout(); } public int getWidth() { return mView.getLayoutParams().width; } }在这个类中提供了width的get和set方法,getWidth()就是获取View当前的宽度,上面说过在没有指定初始值时会调用获得初始值,而setWidth()方法会不断被调用,直至动画结束去改变View的宽度。
ValueAnimator
ValueAnimator是ObjectAnimator的父类,也就可以理解为ObjectAnimator是一个封装好的ValueAnimator,使其使用起来更加的简单。但是作为父类的ValueAnimator也就使用起来更加的灵活多变。ValueAinamtor本身不会作用于任何对象,直接使用不会有动画效果,可以理解为它对一个值做动画,我们通过这个不断变化的值在监听函数中去修改相应的属性。
看看ValueAnimator的几种构造函数:
ofInt(int... values)
ofArgb(int... values)
ofFloat(float... values)
ofPropertyValuesHolder(PropertyValuesHolder... values)
ofObject(TypeEvaluator evaluator, Object... values)
前三种参数都是初始值到结束值的变化范围,很简单
ofPropertyValuesHolder代表多种Animator的集合,下面会介绍具体的使用
ofObject很明显它的参数类型是Object类型,大多是我们自定义的类型,第一个参数TypeEvaluator 是估值器,因为像上面的int之类的系统都有定义相应的估值器所以不需要我们传入,然后我们自定义的Object并没有,所以需要自己的来写。
来看看系统的IntEvaluator
public class IntEvaluator implements TypeEvaluator<Integer> { public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); }}估值器都需要继承自TypeEvaluator,实现里面的evaluate方法,参数分别是完成的百分比,开始值和结束值,文档解释也告诉我们返回的值只需要用结束值减去开始值乘以fraction 然后加上开始值就ok,从而实现值的过渡,所以自定义TypeEvaluator也很简单了。
下面看例子,还是先看效果在撸代码
private void marginValueAnimator() { ValueAnimator valueAnimator = ValueAnimator.ofInt(0, width - mImageView.getWidth()); //监听变化过程 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //获取当前值 int animatedValueMargin = (int) animation.getAnimatedValue(); ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) mImageView.getLayoutParams(); layoutParams.leftMargin = animatedValueMargin; mImageView.setLayoutParams(layoutParams); } }); valueAnimator.setDuration(1000); valueAnimator.setRepeatCount(3); valueAnimator.setRepeatMode(ValueAnimator.REVERSE); valueAnimator.setTarget(mImageView); valueAnimator.start(); }这是个简单的设置view距离左边的动画,构造了ValueAnimator后监听它的更新,在onAnimationUpdate中改变属性值,通过animation.getAnimatedValue()获得当前的值,然后用于更新属性状态,实现动画。
public void scaleValueAnimator() { //1.设置目标属性名及属性变化的初始值和结束值 PropertyValuesHolder mPropertyValuesHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f); PropertyValuesHolder mPropertyValuesHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.0f); ValueAnimator mAnimator = ValueAnimator.ofPropertyValuesHolder(mPropertyValuesHolderScaleX, mPropertyValuesHolderScaleY); //2.为目标对象的属性变化设置监听器 mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 3.根据属性名获取属性变化的值分别为ImageView目标对象设置X和Y轴的缩放值 float animatorValueScaleX = (float) animation.getAnimatedValue("scaleX"); float animatorValueScaleY = (float) animation.getAnimatedValue("scaleY"); mImageView.setScaleX(animatorValueScaleX); mImageView.setScaleY(animatorValueScaleY); } }); //4.为ValueAnimator设置自定义的Interpolator mAnimator.setInterpolator(new CustomInterpolator()); //5.设置动画的持续时间、是否重复及重复次数等属性 mAnimator.setDuration(2000); mAnimator.setRepeatCount(3); mAnimator.setRepeatMode(ValueAnimator.REVERSE); //6.为ValueAnimator设置目标对象并开始执行动画 mAnimator.setTarget(mImageView); mAnimator.start(); }这里通过PropertyValuesHolder来控制实现两种属性的变化,其实这里x和y两个方向的缩放值都是1.0f到0.0f,可以用一个ValueAnimator.ofFloat()来完成,这里主要是为了演示
ofPropertyValuesHolder的使用。
首先是要通过PropertyValuesHolder.ofFloat来创建了两个PropertyValuesHolder对象,其中第一个参数是属性名,可以任意取,可以看到在onAnimationUpdate中通过这个属性名来获取不同PropertyValuesHolder的变化值。然后再通过ValueAnimator.ofPropertyValuesHolder来构造ValueAnimator对象就可以,也很容易看懂。
上面那个类似抛物线的圆是采用ValueAnimator.ofObject来实现的。
1.首先要定义一个Point类,里面用于存放x、y坐标
public class Point { private float x; private float y; public Point(float x, float y) { this.x = x; this.y = y; } public float getX() { return x; } public void setX(int x) { this.x = x; } public float getY() { return y; } public void setY(int y) { this.y = y; }}之前说过要使用ValueAnimator.ofObject需要自定义TypeEvaluator,下面看看定义的PointEvaluator,可以看到和IntEvaluator一样,主要还是计算变化值
public class PointEvaluator implements TypeEvaluator { //TypeEvaluator简单来说是实现了初始值和结束值的平滑过渡 @Override public Object evaluate(float fraction, Object startValue, Object endValue) { Point start = (Point) startValue; Point end = (Point) endValue; //开始值减去结束值乘以fraction再加上开始值就是当前的值 float x = start.getX() + fraction * (end.getX() - start.getX()); float y = start.getY() + fraction * (end.getY() - start.getY()); Point point = new Point(x, y); return point; }下面自定义一个CircleView类
public class CircleView extends View { private static final float Radius = 40.0f; private Point mPoint; private Paint mPaint; public CircleView(Context context) { super(context); } public CircleView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED);// mPoint = new Point(50, 50); } public CircleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { if (mPoint == null) { mPoint = new Point(50, 50); canvas.drawCircle(mPoint.getX(), mPoint.getY(), Radius, mPaint); startAnimation(); } else { canvas.drawCircle(mPoint.getX(), mPoint.getY(), Radius, mPaint); } } private void startAnimation() { //创建开始和结束点坐标 Point start = new Point(50, 50); Point end = new Point(getWidth(), getHeight()); ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), start, end); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //把每一帧的值传给mPoint,绘制界面 mPoint = (Point) animation.getAnimatedValue(); invalidate(); } }); animator.setDuration(5000); animator.start(); }}这个类也比较简单,主要就是在onDraw里面画一个圆,然后根据Point的变化不断调用onDraw方法来改变圆的位置,实现动画,这也就是ValueAnimator.ofObject的用法。
源码下载地址
- Android 动画之属性动画ValueAnimator和ObjectAnimator
- 属性动画ValueAnimator和ObjectAnimator
- android属性动画 —— ValueAnimator和ObjectAnimator的例子
- Android 属性动画ValueAnimator和ObjectAnimator的高级用法
- Android属性动画,ValueAnimator和ObjectAnimator的高级用法
- Android 属性动画valueAnimator和objectAnimator的使用
- Android 属性动画ValueAnimator和ObjectAnimator的高级用法
- Android-Animator属性动画( ObjectAnimator , AnimatorSet , ValueAnimator )
- Android属性动画(ObjectAnimator、PropertyValuesHolder、ValueAnimator、AnimatorSet)
- Android 属性动画,Animator,ValueAnimator,ObjectAnimator, AnimatorSet
- 属性动画ValueAnimator和ObjectAnimator的使用
- android 动画 ValueAnimator 和ObjectAnimator 基本用法
- Android Animation、ObjectAnimator与ValueAnimator实现视图动画和属性动画
- Android属性动画之ObjectAnimator和AnimatorSet
- Android属性动画之ObjectAnimator和AnimatorSet
- Android属性动画之ValueAnimator
- Android属性动画之ValueAnimator
- Android动画学习(三)之使用ValueAnimator和ObjectAnimator实现动画实例
- Android RSA加密解密
- Dubbox的介绍和简单示例
- Java系列-并发性与线程安全
- 显示当前时间代码
- MQTT实现消息推送
- Android 动画之属性动画ValueAnimator和ObjectAnimator
- vim 中Ctags的安装和使用
- JavaScript中的prototype
- SonarQube代码质量管理平台安装及与Jenkins的集成
- NYOJ 2 括号配对问题
- 理解Python中的with…as…语法
- java设计模式之责任链模式
- map遍历的方式
- div 中如何加各种边框(转)