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

 

相關動畫:

  資源文件:

  第一個小球:下落,並且返回:

<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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM