Android Animation学习(四) ApiDemos解析:多属性动画

  如果想同时改变多个属性,根据前面所学的,比较显而易见的一种思路是构造多个对象Animator ,

  ( Animator可以是ValueAnimatorObjectAnimatorAnimatorSet

  然后最后把它们放在一个AnimatorSet中。

  另一种思路就是,把多个属性的改变放在同一个 ValueAnimator 中(ObjectAnimator也是 ValueAnimator)。

  而这就要借助PropertyValuesHolder。本文主要讲这种方法。

  

PropertyValuesHolder

  PropertyValuesHolder是API Level 11加进来的。根据名字就可以判断出它是某种属性的持有者。

  使用工厂方法构造PropertyValuesHolder对象,指定属性名和一系列属性值。

  代码例子:MultiPropertyAnimation中:

                // ============================================================
// 第二个小球:加速下落并且alpha变化
ball = balls.get(1); // 利用ofFloat工厂方法构造PropertyValuesHolder类型对象,控制y属性
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y",
ball.getY(), getHeight() - BALL_SIZE);
// 利用ofFloat工厂方法构造另一个PropertyValuesHolder类型对象,控制alpha属性
PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat(
"alpha", 1.0f, 0f);
// 利用ofPropertyValuesHolder方法来构造ObjectAnimator对象
// 把多个属性变化结合到一个动画中去
ObjectAnimator yAlphaBouncer = ObjectAnimator
.ofPropertyValuesHolder(ball, pvhY, pvhAlpha)
.setDuration(DURATION / 2);
yAlphaBouncer.setInterpolator(new AccelerateInterpolator());
yAlphaBouncer.setRepeatCount(1);
yAlphaBouncer.setRepeatMode(ValueAnimator.REVERSE);

 

关键帧Keyframe

  PropertyValuesHolder的工厂方法里面,除了整形ofInt()、浮点型ofFloat()、Object类型ofObject()之外,还有一种:ofKeyframe()。

  Keyframe类型对象由一个time/value对组成,定义了指定时间点的指定值。

  

  每一个keyframe还可以拥有自己的interpolator,控制了前一个关键帧到这一个关键帧之间的时间动画行为。

  Keyframe 对象的构造也用是工厂方法:ofInt()ofFloat(), or ofObject()

  Keyframe对象构造完之后就可以用 ofKeyframe()工厂方法来构造PropertyValuesHolder对象。

  代码例子:MultiPropertyAnimation中:

                // ============================================================
// 第四个小球:利用关键帧实现曲线运动
ball = balls.get(3);
// 属性1:Y坐标运动:下落
pvhY = PropertyValuesHolder.ofFloat("y", ball.getY(),
getHeight() - BALL_SIZE);
float ballX = ball.getX();
// 三个关键帧
Keyframe kf0 = Keyframe.ofFloat(0f, ballX);
Keyframe kf1 = Keyframe.ofFloat(.5f, ballX + 100f);
Keyframe kf2 = Keyframe.ofFloat(1f, ballX + 50f);
// 属性2:X坐标运动:曲折
// 用三个关键帧构造PropertyValuesHolder对象
PropertyValuesHolder pvhX = PropertyValuesHolder.ofKeyframe(
"x", kf0, kf1, kf2); // 再用两个PropertyValuesHolder对象构造一个ObjectAnimator对象
ObjectAnimator yxBouncer = ObjectAnimator
.ofPropertyValuesHolder(ball, pvhY, pvhX).setDuration(
DURATION / 2);
yxBouncer.setRepeatCount(1);
yxBouncer.setRepeatMode(ValueAnimator.REVERSE);

View的多属性动画:使用ViewPropertyAnimator

  ViewPropertyAnimatorAPI Level 12引进的。

  它是用来做针对View对象的多个属性动画功能。

  (前面的PropertyValuesHolder对象是针对所有对象的,范围更广)。

  如果要同时变换一个View的多个属性的话,ViewPropertyAnimator提供了一种更方便和更适合的方法。

  而且由于多个属性的invalidate方法调用统一管理,而不是之前的分别调用,所以还会有一些性能优化。

  注意 ViewPropertyAnimator 这个类的对象不是由调用者构造的,而是通过View类的animate()方法返回的。

  比如下面的代码对比:给同一个View实现同一个动画效果:

  用多个ObjectAnimator对象:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

  用一个ObjectAnimator对象加多个PropertyValuesHolder:

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

  用ViewPropertyAnimator:

myView.animate().x(50f).y(100f);

API Demos完整代码:

public class MultiPropertyAnimation extends Activity {

    private static final int DURATION = 1500;

    @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_multi_property);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
final MyAnimationView animView = new MyAnimationView(this);
container.addView(animView); Button starter = (Button) findViewById(R.id.startButton);
starter.setOnClickListener(new View.OnClickListener() { public void onClick(View v) {
animView.startAnimation(); }
}); } public class MyAnimationView extends View implements
ValueAnimator.AnimatorUpdateListener { private static final float BALL_SIZE = 100f; public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
AnimatorSet animation = null;
Animator bounceAnim = null;
ShapeHolder ball = null; public MyAnimationView(Context context) {
super(context);
addBall(50, 0);
addBall(150, 0);
addBall(250, 0);
addBall(350, 0);
} private void createAnimation() {
if (bounceAnim == null) {
ShapeHolder ball; // ============================================================
// 第一个小球:弹跳效果
ball = balls.get(0);
ObjectAnimator yBouncer = ObjectAnimator.ofFloat(ball, "y",
ball.getY(), getHeight() - BALL_SIZE).setDuration(
DURATION);
yBouncer.setInterpolator(new BounceInterpolator());
yBouncer.addUpdateListener(this); // ============================================================
// 第二个小球:加速下落并且alpha变化
ball = balls.get(1); // 利用ofFloat工厂方法构造PropertyValuesHolder类型对象,控制y属性
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y",
ball.getY(), getHeight() - BALL_SIZE);
// 利用ofFloat工厂方法构造另一个PropertyValuesHolder类型对象,控制alpha属性
PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat(
"alpha", 1.0f, 0f);
// 利用ofPropertyValuesHolder方法来构造ObjectAnimator对象
// 把多个属性变化结合到一个动画中去
ObjectAnimator yAlphaBouncer = ObjectAnimator
.ofPropertyValuesHolder(ball, pvhY, pvhAlpha)
.setDuration(DURATION / 2);
yAlphaBouncer.setInterpolator(new AccelerateInterpolator());
yAlphaBouncer.setRepeatCount(1);
yAlphaBouncer.setRepeatMode(ValueAnimator.REVERSE); // ============================================================
// 第三个小球:宽度,高度,x,y同时变化
ball = balls.get(2);
PropertyValuesHolder pvhW = PropertyValuesHolder.ofFloat(
"width", ball.getWidth(), ball.getWidth() * 2);
PropertyValuesHolder pvhH = PropertyValuesHolder.ofFloat(
"height", ball.getHeight(), ball.getHeight() * 2);
PropertyValuesHolder pvTX = PropertyValuesHolder.ofFloat("x",
ball.getX(), ball.getX() - BALL_SIZE / 2f);
PropertyValuesHolder pvTY = PropertyValuesHolder.ofFloat("y",
ball.getY(), ball.getY() - BALL_SIZE / 2f);
// 利用ofPropertyValuesHolder方法来构造ObjectAnimator对象
// 因为是可变参数,所以PropertyValuesHolder对象的个数不限
ObjectAnimator whxyBouncer = ObjectAnimator
.ofPropertyValuesHolder(ball, pvhW, pvhH, pvTX, pvTY)
.setDuration(DURATION / 2);
whxyBouncer.setRepeatCount(1);
whxyBouncer.setRepeatMode(ValueAnimator.REVERSE); // ============================================================
// 第四个小球:利用关键帧实现曲线运动
ball = balls.get(3);
// 属性1:Y坐标运动:下落
pvhY = PropertyValuesHolder.ofFloat("y", ball.getY(),
getHeight() - BALL_SIZE);
float ballX = ball.getX();
// 三个关键帧
Keyframe kf0 = Keyframe.ofFloat(0f, ballX);
Keyframe kf1 = Keyframe.ofFloat(.5f, ballX + 100f);
Keyframe kf2 = Keyframe.ofFloat(1f, ballX + 50f);
// 属性2:X坐标运动:曲折
// 用三个关键帧构造PropertyValuesHolder对象
PropertyValuesHolder pvhX = PropertyValuesHolder.ofKeyframe(
"x", kf0, kf1, kf2); // 再用两个PropertyValuesHolder对象构造一个ObjectAnimator对象
ObjectAnimator yxBouncer = ObjectAnimator
.ofPropertyValuesHolder(ball, pvhY, pvhX).setDuration(
DURATION / 2);
yxBouncer.setRepeatCount(1);
yxBouncer.setRepeatMode(ValueAnimator.REVERSE); // ===========================================================
// 所有小球动画的集合
bounceAnim = new AnimatorSet();
((AnimatorSet) bounceAnim).playTogether(yBouncer,
yAlphaBouncer, whxyBouncer, yxBouncer);
}
} public void startAnimation() {
createAnimation();
bounceAnim.start();
} private ShapeHolder addBall(float x, float y) {
OvalShape circle = new OvalShape();
circle.resize(BALL_SIZE, BALL_SIZE);
ShapeDrawable drawable = new ShapeDrawable(circle);
ShapeHolder shapeHolder = new ShapeHolder(drawable);
shapeHolder.setX(x);
shapeHolder.setY(y);
int red = (int) (100 + Math.random() * 155);
int green = (int) (100 + Math.random() * 155);
int blue = (int) (100 + Math.random() * 155);
int color = 0xff000000 | red << 16 | green << 8 | blue;
Paint paint = drawable.getPaint();
int darkColor = 0xff000000 | red / 4 << 16 | green / 4 << 8 | blue
/ 4;
RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 50f,
color, darkColor, Shader.TileMode.CLAMP);
paint.setShader(gradient);
shapeHolder.setPaint(paint);
balls.add(shapeHolder);
return shapeHolder;
} @Override
protected void onDraw(Canvas canvas) {
for (ShapeHolder ball : balls) {
canvas.translate(ball.getX(), ball.getY());
ball.getShape().draw(canvas);
canvas.translate(-ball.getX(), -ball.getY());
}
} public void onAnimationUpdate(ValueAnimator animation) {
invalidate();
} }
}

  

参考资料:

  API Guides:Property Animation

  http://developer.android.com/guide/topics/graphics/prop-animation.html

  项目地址:https://github.com/mengdd/AnimationApiDemos.git

Android Animation学习(四) ApiDemos解析:多属性动画的更多相关文章

  1. Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition

    Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition Property animation系统还提供了对ViewGroup中的View改变 ...

  2. Android Animation学习(三) ApiDemos解析:XML动画文件的使用

    Android Animation学习(三) ApiDemos解析:XML动画文件的使用 可以用XML文件来定义Animation. 文件必须有一个唯一的根节点: <set>, <o ...

  3. Android Animation学习(二) ApiDemos解析:基本Animators使用

    Android Animation学习(二) ApiDemos解析:基本Animatiors使用 Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.O ...

  4. Android Animation学习(二) ApiDemos解析:基本Animatiors使用

    Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.ObjectAnimator.AnimatorSet ApiDemos中Animation部分是单独 ...

  5. Android Animation学习(六) View Animation介绍

    Android Animation学习(六) View Animation介绍 View Animation View animation系统可以用来执行View上的Tween animation和F ...

  6. Android Animation学习(一) Property Animation原理介绍和API简介

    Android Animation学习(一) Property Animation介绍 Android Animation Android framework提供了两种动画系统: property a ...

  7. Android JNI学习(四)——JNI的常用方法的中文API

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  8. Android Animation学习笔记

    原文地址: http://www.cnblogs.com/feisky/archive/2010/01/11/1644482.html 关于动画的实现,Android提供了Animation,在And ...

  9. Android animation学习笔记之view/drawable animation

    前一章中总结了android animation中property animation的知识和用法,这一章总结View animation和Drawable animation的有关知识: View ...

随机推荐

  1. js实现对json数据的序列化(兼容ie6以上浏览器)

    /** * 增加对JSON数据的序列化方法, * 主要用于IE6.7不支持JSON对象的浏览器 */ var xue = xue || {};xue.json = xue.json || {}; xu ...

  2. MySQL修改默认字符集

    今天朋友在做某个程序项目时,需要修改MySQL修改默认字符集,搞不好找我帮忙.百度了试了好几篇博文中的方法,最后终于成功了.但是感觉那些博文思路有点乱,所以自己总结下,希望可以帮到遇到同样问题的人. ...

  3. 第3/24周 区_SQL Server中管理空间的基本单位

    哇哦,SQL Server性能调优培训已经进入第3周了!同时你已经对SQL Server内核运行机制有了很好的认识.今天我会讲下SQL Server中的区管理,因为这是个很重要的话题,我们会在第23周 ...

  4. Microsoft Orleans 之 入门指南

    Microsoft Orleans 在.net用简单方法构建高并发.分布式的大型应用程序框架. 原文:http://dotnet.github.io/orleans/ 在线文档:http://dotn ...

  5. html的块级、内联、内联块级元素基础

    概念 块级:block 内联:inline 内联块级:inline-block 在html元素中,元素会有display属性 display属性默认值是block,那么该元素是块级元素. displa ...

  6. 基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

    最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重 ...

  7. 分享一个递归无限级拼接Json的方法---ExtJs的TreePanel和TreeGrid均适用(Ef,Lambda,Linq,IQueryable,List)

    话不多说,先上实体类,如果你不是codefirst,就把它当成数据表结构. 下面是底层BaseDal获取数据的方法  (如果你没有Base类,直接写在你的DAL层和BLL层) 下面是BaseServi ...

  8. 走进异步世界:EnyimMemcached异步化改造引起的内存泄漏

    6月30日我们发布了异步化改造后的博客程序之后,出现了高内存.高CPU.高线程数的不理想情况. 经过一周的追查,终于水落日出——引起不理想情况的根源是我们修改过的EnyimMemcached代码存在内 ...

  9. 自己动手,让Entity Framework Power Tools在VS2015重放光彩

    Entity Framework Power Tools是一个由EntityFramework开发小组提供的工具,它可以从现有数据库生成Fluent款式的Code First代码. VS Galler ...

  10. java中实现同步的两种方式:syschronized和lock的区别和联系

    Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...