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());
        }
    }
}

相关动画:

  资源文件:

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

<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

时间: 2024-10-03 21:20:15

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

Android开发学习---使用XmlPullParser解析xml文件

Android中解析XML的方式主要有三种:sax,dom和pull关于其内容可参考:http://blog.csdn.net/liuhe688/article/details/6415593 本文将主要介绍pull解析器解析xml文件,环境为ubuntu 12.04+ intelij 13.1 + android sdk 2.1 一.创建一个XML项目,步骤如下: 二.解析一个xml文件: assets/person.xml <?xml version="1.0" encodi

Android Animation学习 实现 IOS 滤镜退出动画

IOS的用户体验做的很好,其中一点很重要的地方就是动画效果. 最近在学习Android的Animation,简单实现了一个IOS相机滤镜退出的动画: 布局文件:activity_animation_demo.xml  布局未考虑各个分辨率,只是为了实现动画逻辑,(代码测试是在720P分辨率的手机上) 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools=

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

Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.ObjectAnimator.AnimatorSet ApiDemos中Animation部分是单独的一个包. 下面代码来自ApiDemos中的AnimationCloning类,加了一个使用ValueAnimator的动画,还有一些注释. 完整的项目见:URL:https://github.com/mengdd/AnimationApiDemos.git package com.example.

Android 学习之pull解析Xml

一. PUll解析Xml public static List<Person> xmlParser(InputStream xml) throws Exception { List<Person> persons=null; Person p=null; XmlPullParser parser=Xml.newPullParser(); parser.setInput(xml, "UTF-8"); int event=parser.getEventType();

Qt中三种解析xml的方式

在下面的随笔中,我会根据xml的结构,给出Qt中解析这个xml的三种方式的代码.虽然,这个代码时通过调用Qt的函数实现的,但是,很多开源的C++解析xml的库,甚至很多其他语言解析xml的库,都和下面三种解析xml采用相同的原理,所以就算你不是学习qt,也可以大致参看一下代码,对三种解析方式有一种大致的感觉. 先给出xml如下: <?xml version="1.0" encoding="utf-8"?> <school> <teach

android如何使用DOM来解析XML文件

对于以下的xml文件: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <books> <book email="zhoujunhui&quo

android如何使用DOM来解析XML+如果做一个表情的弹出框

效果图: 如何解析以下的xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <array> <string>(#大笑)</string

android网络编程之pull解析xml

android网络编程之pull解析xml 除了前面介绍过的SAX以及DOM方法,还可以通过Pull对xml文档进行一个解析.Pull解析器的解析方式与SAX非常相似.它提供了类似的事件,使用parser.next()可以进入下一元素并触发相应事件,事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行选择,然后进行相应的处理,调用parser.nextText()方法可以获取下一个Text类型元素的值. pull解析器特点: *结构简单:一个接口.一个例外.一个工厂就组成了P

使用第三方DOM解析XML格式文件

在解析XML格式文件的时候,使用SAX解析需要实现好多代理方法,比较难记,也容易出错,现在介绍一种由Google推出的第三方DOM(Document Object Model)来解析XML文件. 首先将该第三方文件拖到工程中.谷歌下载地址:https://code.google.com/p/gdata-objectivec-client/source/browse/trunk/Source/XMLSupport/ (注:由于该三方是很久之前的版本,还是基于MRC格式下的代码,所以需要改成ARC兼