Android的三種動畫

Android動畫詳解

幀動畫

  所謂幀動畫其實很好理解,就是通過在一定的時間間隔內,將一組圖片順序播放出來,從而打到動畫的效果,我們通過簡單的幀動畫例子來說明一下。
  下面是幀動畫的xml資源代碼,animation-list就是幀動畫的標籤,它包含的item就是每一幀的圖像。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@mipmap/one"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/two"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/three"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/four"
        android:duration="500"/>
    <item
        android:drawable="@mipmap/five"
        android:duration="50"/>
    <item
        android:drawable="@mipmap/six"
        android:duration="50"/>
</animation-list>

  接下來我們創建幀動畫例子activity的佈局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="開始"
        android:id="@+id/start"
        android:layout_marginTop="20dp"
        android:onClick="onStart"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:id="@+id/stop"
        android:text="停止"
        android:onClick="onStop"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop ="20dp"
        android:id="@+id/imageView"/>

</LinearLayout>

  然後是activity裏面的代碼

public class FrameAnimationActivity extends AppCompatActivity {
    private AnimationDrawable animationDrawable; //此處寫錯了 寫成了Animation
    private ImageView imageView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.frame_activity);
        init();
    }
    private void init(){
        imageView = (ImageView)findViewById(R.id.imageView);

        imageView.setBackgroundResource(R.drawable.frame_anim);

        animationDrawable = (AnimationDrawable) imageView.getBackground();
    }

    public void onStart(View view){
        if(animationDrawable != null && !animationDrawable.isRunning()){
            animationDrawable.start();
        }
    }

    public void onStop(View view){
        if(animationDrawable != null && animationDrawable.isRunning()){
            animationDrawable.stop();
        }
    }
}

  通過上面的代碼可以知道,幀動畫主要需要記住3點,1是動畫資源文件-drawable裏面的文件,animation-list以及它的子標籤item。2是AnimationDrawable這個類以及這個類的實例對象通過imageView控件的getBackground方法得到的。3是AnimationDrawable的用法(start()、stop()這個幾個方法)。

補間動畫

  補間動畫主要有四種操作:透明變化、縮放控制、旋轉控制、移動控制。這四種動畫變化都是通過資源文件來實現的,我們在res文件夾裏面創建anim文件夾。然後根據需要創建相應的xml文件,這裏通過一個例子說明用法。
  下面是alpha、scale、rotate、translate、set對應的xml文件,set文件是將上面所有動畫種類選擇性地集合在一起,同時執行。

  • alpha.xml
<?xml version="1.0" encoding="utf-8" ?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromAlpha="0"
    android:toAlpha="1"
    android:duration="4000"/>
    
<!-- interpolator:表示採用這個算法,設置動畫播放的平緩的程度 -->
<!-- fromAlpha:初始透明度-->
<!-- toAlpha:最終透明度-->
  • scale.xml
<?xml version="1.0" encoding="utf-8" ?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromYScale="0"
    android:fromXScale="0"
    android:toXScale="1"
    android:toYScale="1"
    android:pivotY="0"
    android:pivotX="100%"
    android:duration="3000"/>

<!-- 縮放的的基點 pivotX和pivotY  如果在百分號數值後面加一個p,就是控件左上角加上父控件百分之多少的值-->
<!-- fromYScale:初始Y軸的縮放比例-->
<!-- fromXScale:初始X軸的縮放比例-->
<!-- toYScale:最終Y軸的縮放比例-->
<!-- toXScale:最終X軸的縮放比例-->

  • rotate.xml
<?xml version="1.0" encoding="utf-8" ?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:pivotX="50%"
    android:pivotY="30%"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:duration="3000"/>

    <!-- 旋轉的的基點 pivotX和pivotY  如果在百分號數值後面加一個p,就是控件左上角加上父控件百分之多少的值-->
  • translate.xml
<?xml version="1.0" encoding="utf-8" ?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toYDelta="500"
    android:toXDelta="500"
    android:duration="3000"/>
  • set.xml
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:shareInterpolator="true">


    <scale
        android:pivotY="50%"
        android:pivotX="50%"
        android:fromXScale="0"
        android:fromYScale="0"
        android:toYScale="1"
        android:toXScale="1"
        android:duration="1000"/>

<!-- 會覆蓋前面的scale動畫-->

    <scale
        android:pivotY="50%"
        android:pivotX="50%"
        android:fromXScale="1"
        android:fromYScale="1"
        android:toYScale="0"
        android:toXScale="0"
        android:duration="1000"/>

    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="1000"/>
</set>

  補間動畫的佈局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="透明動畫"
        android:onClick="onAlpha"
        android:layout_marginTop="20dp"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:onClick="onScale"
        android:text="縮放動畫"/>

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:onClick="onRotate"
        android:text="旋轉動畫"/>

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:onClick="onTranslate"
        android:text="位移動畫"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:onClick="onSet"
        android:text="動畫組合"/>

    <ImageView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_gravity="center_horizontal"
        android:id="@+id/imageView"
        android:background="@mipmap/five"/>

</LinearLayout>

  activity代碼

public class TweenAnimationActivity extends AppCompatActivity {

    private Animation animation;
    private ImageView imageView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tween_activity);

        init();
    }

    private void init(){
        imageView = (ImageView)findViewById(R.id.imageView);
    }
    public void onAlpha(View view){
        animation = AnimationUtils.loadAnimation(this, R.anim.alpha);
        imageView.startAnimation(animation);
    }
    public void onScale(View view){
        animation = AnimationUtils.loadAnimation(this, R.anim.scale);
        imageView.startAnimation(animation);

    }
    public void onRotate(View view){
        animation = AnimationUtils.loadAnimation(this, R.anim.rotate);
        imageView.startAnimation(animation);
    }
    public void onTranslate(View view){
        animation = AnimationUtils.loadAnimation(this, R.anim.translate);
        imageView.startAnimation(animation);
    }

    /**
     *
     * @param view
     *
     * 對於set的理解就是,set.xml文件裏面定義這四種動畫,然後同時執行,也可以定義一樣的動畫類型,但是會覆蓋前面的同類型動。
     */

    public void onSet(View view){
        animation = AnimationUtils.loadAnimation(this, R.anim.set);
        imageView.startAnimation(animation);
    }
}

  通過上面示例代碼可以看出。補間動畫主要記住3點,1是補間動畫資源文件的寫法,2是Animation類和AnimationUtils類loadAnimation()方法的用法, 3是插值器,參考這篇文章

屬性動畫

  屬性動畫需要和補間動畫區分開來,因爲前者的變化是真實的,後者的變化是不真實的,補間動畫只是給人一種障眼法,比如當補間動畫移動之後,你點擊它的顯示區域,發現不會響應點擊事件,只有點擊它的原始區域纔會響應點擊事件。而屬性動畫就不一樣了,只要移動在屏幕可顯示區域就可以響應點擊事件。同樣地給出一個例子來說明。

  • 佈局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:onClick="onAlpha"
        android:text="透明"/>
    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:onClick="onScale"
        android:text="縮放"/>
    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:onClick="onRotate"
        android:text="旋轉"/>
    <Button
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:onClick="onTranslate"
        android:text="移動"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onSet"
        android:text="集合"/>

    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_gravity="center_horizontal"
        android:text="我是移動的控件"
        android:id="@+id/move_button"/>

</LinearLayout>
  • activity代碼
public class AttributeAnimationActivity extends AppCompatActivity {
    private ObjectAnimator objectAnimator;
    private Button show_button;
    private final static String TAG = "提示";

    private AnimatorSet animatorSet = new AnimatorSet();
    ObjectAnimator rotateObjectAnimator1 = new ObjectAnimator();
    ObjectAnimator translateObjectAnimator1 = new ObjectAnimator();
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.attribute_activity);
        init();

        animatorSet.addListener(new AnimatorListenerAdapter() {

            private AnimatorSet animatorSet2 = new AnimatorSet();

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
//                animation.cancel();
                Log.d(TAG, "onAnimationEnd: 動畫完成,開始回來動畫");
                ObjectAnimator rotateObjectAnimator2 = new ObjectAnimator();
                ObjectAnimator translateObjectAnimator2 = new ObjectAnimator();

                rotateObjectAnimator2 = rotateObjectAnimator2.ofFloat(show_button, "rotation", 0f, 360f);
                translateObjectAnimator2 = translateObjectAnimator2.ofFloat(show_button, "translationY", 200f, 150f, 100f, 50f, 0f);

                animatorSet2.setDuration(2000);

                animatorSet2.play(rotateObjectAnimator2).with(translateObjectAnimator2);
                animatorSet2.start();
            }

        });
    }
    private void init(){
        show_button = (Button)findViewById(R.id.move_button);
    }

    public void onAlpha(View view){
        Log.d(TAG, "onAlpha: ");
        //value是不定長形參數組。裏面的值代表動畫的變化過程值。
        objectAnimator = objectAnimator.ofFloat(show_button, "alpha", 1f, 0.5f, 0f, 0.5f, 1f);
        objectAnimator.setDuration(2000);
        objectAnimator.start();
    }

    public void onScale(View view){
        Log.d(TAG, "onScale: ");
        objectAnimator = objectAnimator.ofFloat(show_button, "scaleY", 0f, 1f, 2f, 1f);
        objectAnimator.setDuration(2000);
        objectAnimator.start();
    }

    public void onRotate(View view){
        Log.d(TAG, "onRotate: ");
        objectAnimator = objectAnimator.ofFloat(show_button, "rotation", 0f, 90f, 360f);
        objectAnimator.setDuration(2000);
        objectAnimator.setRepeatCount(3);
        objectAnimator.setRepeatMode(ValueAnimator.RESTART);
        objectAnimator.start();
    }
    public void onTranslate(View view){
        Log.d(TAG, "onTranslate: ");
        objectAnimator = objectAnimator.ofFloat(show_button, "translationY", 0f, 50f, 100f, 150f, 200f);
        objectAnimator.setDuration(2000);
        objectAnimator.start();
    }

    public void onSet(View view){
        Log.d(TAG, "onSet: ");
        rotateObjectAnimator1 = rotateObjectAnimator1.ofFloat(show_button, "rotation", 0f, 90f,  360f);
        translateObjectAnimator1 = translateObjectAnimator1.ofFloat(show_button, "translationY", 0f, 50f, 100f, 150f, 200f);


        animatorSet.setDuration(2000);
        animatorSet.play(rotateObjectAnimator1).with(translateObjectAnimator1);
        animatorSet.start();
    }
}

  屬性動畫需要記住3點,1是屬性動畫不依賴xml文件。2是ObjectAnimator類以及它的ofFloat()方法的用法。3是AnimatorSet類的用法。

總結

  Android動畫類型從簡單到複雜是,幀動畫-補間動畫-屬性動畫。同時靈活程度也是如此,幀動畫可以實現一些簡單的顯示效果,如果想要移動、旋轉等操作就需要用到補間動畫了,而如果要實現是跟爲複雜或者可響應點擊事件的功能,那就只能選擇屬性動畫了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章