可以用XML文件来定义Animation。
文件必须有一个唯一的根节点:
<set>, <objectAnimator>, or <valueAnimator>三者之一。
对应的Java类是:
- - <animator>
- - <objectAnimator>
- - <set>
<set>标签是可以嵌套的。
<set>标签的android:ordering属性规定了这个set中的动画的执行顺序。该属性值默认是together (default)。
比如:
使用时:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator( myContext, R.anim.property_animator); set.setTarget(myObject); set.start();
为了区分Property animation和View animation的资源文件,从Android 3.1开始,Property animation的xml文件存在res/animator/目 录下(View animation的存在res/anim/目录下), animator这个名是可选的。但是如果你想要使用Eclipse ADT plugin (ADT 11.0.0+)的布局编辑器,你就必须使用res/animator/目录,因为ADT只在该目录下寻找property animation的资源文件。
Api Demo相关代码:
代码结构和上一篇文章中的基本类似,也是各种小球的动画,只不过这次的动画效果都是从XML文件中读取的。
完整的项目见项目地址:
public class AnimationFromXmlActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置布局,布局xml中只包含了一个线性布局和一个Button setContentView(R.layout.animation_basic); LinearLayout container = (LinearLayout) findViewById(R.id.container); // 将自定义的View加入到线性布局中 final MyAnimationView animView = new MyAnimationView(this); container.addView(animView); // Button的点击事件即动画开始 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 ArrayListballs = new ArrayList (); Animator animation = null; public MyAnimationView(Context context) { super(context); addBall(50, 50); addBall(200, 50); addBall(350, 50); addBall(500, 50, Color.GREEN); } private void createAnimation() { Context appContext = AnimationFromXmlActivity.this; if (animation == null) { // ======================================================== // 载入根节点为 的xml资源文件,解析放进ObjectAnimator类对象 ObjectAnimator anim = (ObjectAnimator) AnimatorInflater .loadAnimator(appContext, R.anim.object_animator); anim.addUpdateListener(this); anim.setTarget(balls.get(0)); // ======================================================== // 载入根节点为 的xml资源文件,解析放进ValueAnimator类对象 ValueAnimator fader = (ValueAnimator) AnimatorInflater .loadAnimator(appContext, R.anim.animator); fader.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { invalidate(); // ValueAnimator动画需要在监听器中自己设置对象的属性值 // 这里改变的是alpha值 balls.get(1).setAlpha( (Float) animation.getAnimatedValue()); } }); // ======================================================== // 载入根节点为 的xml资源文件,解析放进AnimatorSet类对象 AnimatorSet seq = (AnimatorSet) AnimatorInflater.loadAnimator( appContext, R.anim.animator_set);// x和y属性同时改变的动画集合 seq.setTarget(balls.get(2)); // 这里要注意:因为AnimatorSet没有设置AnimatorUpdateListener的方法, // 所以如果其他动画没有设置AnimatorUpdateListener来进行View的invalidate()刷新, // 这个AnimatorSet seq是不刷新的 // ======================================================== // 载入根节点为 的xml资源文件,解析放进ObjectAnimator类对象 ObjectAnimator colorizer = (ObjectAnimator) AnimatorInflater .loadAnimator(appContext, R.anim.color_animator); colorizer.setTarget(balls.get(3)); colorizer.addUpdateListener(this); // ======================================================== // 总的AnimationSet,所有的动画同时播放 animation = new AnimatorSet(); ((AnimatorSet) animation).playTogether(anim, fader, seq, colorizer); } } public void startAnimation() { createAnimation(); animation.start(); } private ShapeHolder createBall(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); return shapeHolder; } private void addBall(float x, float y, int color) { ShapeHolder shapeHolder = createBall(x, y); shapeHolder.setColor(color); balls.add(shapeHolder); } private void addBall(float x, float y) { ShapeHolder shapeHolder = createBall(x, 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 = shapeHolder.getShape().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); balls.add(shapeHolder); } @Override protected void onDraw(Canvas canvas) { // 遍历并绘制每一个球形对象 for (ShapeHolder ball : balls) { // 这里是canvas.translate到一个地方,进行绘制,之后再translate回来 // 跟先save后restore的作用相同 canvas.translate(ball.getX(), ball.getY()); ball.getShape().draw(canvas); canvas.translate(-ball.getX(), -ball.getY()); } } public void onAnimationUpdate(ValueAnimator animation) { // 刷新View invalidate(); // 因为第一个小球用的是ObjectAnimator,所以这里不必要自己设置属性值 // 如果是ValueAnimator就需要加上下面两行 // ShapeHolder ball = balls.get(0); // ball.setY((Float) animation.getAnimatedValue()); } } }
相关动画:
资源文件:
第一个小球:下落,并且返回:
第二个小球:消失(变为透明),然后再出现:
第三个小球:X轴与Y轴同时运动,并且返回:
参考资料
API Guides:
项目地址: