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

 

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

 

  可以用XML文件来定义Animation。

  文件必须有一个唯一的根节点:

  <set>, <objectAnimator>, or <valueAnimator>三者之一。

  对应的Java类是:

 

  <set>标签是可以嵌套的。

  <set>标签的android:ordering属性规定了这个set中的动画的执行顺序。该属性值默认是together (default)。

  比如:

<set android:ordering="sequentially" >



    <set>

        <objectAnimator

            android:duration="500"

            android:propertyName="x"

            android:valueTo="400"

            android:valueType="intType" />

        <objectAnimator

            android:duration="500"

            android:propertyName="y"

            android:valueTo="300"

            android:valueType="intType" />

    </set>



    <objectAnimator

        android:duration="500"

        android:propertyName="alpha"

        android:valueTo="1f" />



</set>

 

  

  使用时:

        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文件中读取的。

  完整的项目见项目地址:https://github.com/mengdd/AnimationApiDemos.git

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 ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();

        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) {



                // ========================================================

                // 载入根节点为<objectAnimator>的xml资源文件,解析放进ObjectAnimator类对象

                ObjectAnimator anim = (ObjectAnimator) AnimatorInflater

                        .loadAnimator(appContext, R.anim.object_animator);

                anim.addUpdateListener(this);

                anim.setTarget(balls.get(0));



                // ========================================================

                // 载入根节点为<animator>的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());

                    }

                });



                // ========================================================

                // 载入根节点为<set>的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是不刷新的



                // ========================================================

                // 载入根节点为<objectAnimator>的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());

        }

    }

}

 

相关动画:

  资源文件:

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

  第一个小球:下落,并且返回:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"

    android:duration="1000"

    android:valueTo="200"

    android:valueType="floatType"

    android:propertyName="y"

    android:repeatCount="1"

    android:repeatMode="reverse"/>

  第二个小球:消失(变为透明),然后再出现:

<animator xmlns:android="http://schemas.android.com/apk/res/android"

    android:duration="1000"

    android:valueFrom="1"

    android:valueTo="0"

    android:valueType="floatType"

    android:repeatCount="1"

    android:repeatMode="reverse"/>

 

  第三个小球:X轴与Y轴同时运动,并且返回:

<set>

    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"

        android:duration="1000"

        android:valueTo="200"

        android:valueType="floatType"

        android:propertyName="x"

        android:repeatCount="1"

        android:repeatMode="reverse"/>

    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"

        android:duration="1000"

        android:valueTo="400"

        android:valueType="floatType"

        android:propertyName="y"

        android:repeatCount="1"

        android:repeatMode="reverse"/>

</set>


  第四个小球:颜色变化:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"

    android:duration="1000"

    android:valueFrom="#0f0"

    android:valueTo="#00ffff"

    android:propertyName="color"

    android:repeatCount="1"

    android:repeatMode="reverse"/>

 

 

参考资料

  API Guides:Declaring Animations in XML

  Animation Resources

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

你可能感兴趣的:(animation)