1. 程式人生 > >android中的動畫完全總結

android中的動畫完全總結

這裡會講到的動畫有檢視動畫(幀動畫,補間動畫),屬性動畫,activity和fragment切換時的動畫,viewgroup新增和移除子view時的動畫,android隨後新的系統api的transition,Scene實現過渡效果,內容還是很多的。下面一一來說。

在Android動畫中,總共有兩種型別的動畫View Animation(檢視動畫)和Property Animator(屬性動畫);其中 
View Animation包括Tween Animation(補間動畫)和Frame Animation(逐幀動畫); 
Property Animator包括ValueAnimator和ObjectAnimation;

1.幀動畫:

<span style="font-size:14px;">	/**
	 * 幀動畫就是搞幾個圖片讓他輪播
	 * 在res/drawable下定義xml檔案
	 * <?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" 
    android:oneshot="true">
    <item
        android:drawable="@drawable/iv1"
        android:duration="150">
    </item>
    <item
        android:drawable="@drawable/iv2"
        android:duration="150">
    </item>
    <item
        android:drawable="@drawable/iv3"
        android:duration="150">
    </item>
</animation-list>
將xml作為imageview的背景圖片
程式碼中呼叫 imageview.getbackground強轉為AnimationDrawable
呼叫start..
呼叫stop
	 */</span>
2.補間動畫:有xml定義或者java檔案定義都可以

xml中定義:

<span style="font-size:14px;">	 * Android的animation由四種類型組成:alpha、scale、translate、rotate
	 * 還有個動畫集合set可以把以上動畫放在一起同時執行
	 * 可以用xml檔案定義res/anim資料夾下
	 * 
	 * 1.scale標籤是縮放動畫,可以實現動態調控制元件尺寸的效果,有下面幾個屬性:
android:fromXScale    起始的X方向上相對自身的縮放比例,浮點值,比如1.0代表自身無變化,0.5代表起始時縮小一倍,2.0代表放大一倍;
android:toXScale        結尾的X方向上相對自身的縮放比例,浮點值;
android:fromYScale    起始的Y方向上相對自身的縮放比例,浮點值,
android:toYScale        結尾的Y方向上相對自身的縮放比例,浮點值;
android:pivotX            縮放起點X軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p,當為數值時,表示在當前View的左上角,即原點處加上50px,做為起始縮放點;如果是50%,表示在當前控制元件的左上角加上自己寬度的50%做為起始點;如果是50%p,那麼就是表示在當前的左上角加上父控制元件寬度的50%做為起始點x軸座標。(具體意義,後面會舉例演示)
android:pivotY           縮放起點Y軸座標,取值及意義跟android:pivotX一樣。
	 * 
	 * 
	 * android:fillAfter   如果設定為true,控制元件動畫結束時,將保持動畫最後時的狀態
	 * android:fillBefore       如果設定為true,控制元件動畫結束時,還原到開始動畫前的狀態
	 *android:repeatCount 重複次數
android:repeatMode	重複型別,有reverse和restart兩個值,reverse表示倒序回放,restart表示重新放一遍,必須與repeatCount一起使用才能看到效果。因為這裡的意義是重複的型別,即回放時的動作。
android:interpolator  設定插值器,其實就是指定的動作效果,比如彈跳效果等,不在這小節中講解,後面會單獨列出一單講解。
	 * 
	 * 
	 * 2.
	 * alpha標籤——調節透明度
1、自身屬性
android:fromAlpha   動畫開始的透明度,從0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
android:toAlpha       動畫結束時的透明度,也是從0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
	 
	 
	 3.Rotate
	 android:fromDegrees     開始旋轉的角度位置,正值代表順時針方向度數,負值程式碼逆時針方向度數
android:toDegrees         結束時旋轉到的角度位置,正值代表順時針方向度數,負值程式碼逆時針方向度數
android:pivotX               縮放起點X軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p,具體意義已在scale標籤中講述,這裡就不再重講
android:pivotY               縮放起點Y軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p
	
	
	4.translate標籤所具有的屬性為:
android:fromXDelta     起始點X軸座標,可以是數值、百分數、百分數p 三種樣式,比如 50、50%、50%p,具體意義已在scale標籤中講述,這裡就不再重講
android:fromYDelta    起始點Y軸從標,可以是數值、百分數、百分數p 三種樣式;
android:toXDelta         結束點X軸座標
android:toYDelta        結束點Y軸座標
	 *
	 */</span>

除了上面4個外,還有一個AnimationSet,是可以將上面動畫組合在一起的。

xml中定義後,使用下面的程式碼應用動畫,

<span style="font-size:14px;">	public static void start(View view){
//		AnimationSet set = new AnimationSet(true);
//		set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.scale_anim));
//		set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.alpha_anim));
//		set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.rotate_anim));
//
//		set.setAnimationListener(new AnimationListener() {
//			@Override
//			public void onAnimationStart(Animation animation) {
//			}
//
//			@Override
//			public void onAnimationRepeat(Animation animation) {
//			}
//
//			@Override
//			public void onAnimationEnd(Animation animation) {
//				view.startAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.translate_anim));
//			}
//		});
//		view.startAnimation(set);
		
		view.startAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.set_anim));
	}</span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <alpha
        android:duration="2500"
        android:fromAlpha="0"
        android:toAlpha="1" />
</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set>

    <rotate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    </rotate>

</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    
  <scale xmlns:android="http://schemas.android.com/apk/res/android"  
    android:fromXScale="0"
    android:toXScale="1"  
    android:fromYScale="0"  
    android:toYScale="1"  
    android:pivotX="67%p"  
    android:pivotY="67%p"  
    android:duration="2500" />

</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="67%p"
        android:toYDelta="67%p" >
    </translate>

</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <rotate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    </rotate>

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

    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="67%p"
        android:pivotY="67%p"
        android:toXScale="1"
        android:toYScale="1" />

    <translate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:startOffset="2500"
        android:toXDelta="67%p"
        android:toYDelta="67%p" >
    </translate>

</set></span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000" >

    <translate
        android:fromXDelta="-50%p"
        android:toXDelta="0" />

    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

</set></span>

java程式碼建立補間動畫,

只是根據xml中定義的,翻譯成java程式碼就可以了。

如xml中定義了,

<span style="font-size:14px;">	/**
	 * 程式碼生成animation。xml檔案對應的Java類
	 * 	TranslateAnimation
		RotateAnimation
		ScaleAnimation
		AlphaAnimation
		我們可以根據xml中的屬性翻譯過來就行了
	 */
	
	//例如這個:
	/**
	 * <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <rotate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    </rotate>

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

    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="67%p"
        android:pivotY="67%p"
        android:toXScale="1"
        android:toYScale="1" />

    <translate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:startOffset="2500"
        android:toXDelta="67%p"
        android:toYDelta="67%p" >
    </translate>

</set>
	 */</span>

那麼如果我們用java程式碼來生成的話就是這樣的:
<span style="font-size:14px;">	public static void start(View view){
		RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		rotateAnimation.setFillAfter(true);
		rotateAnimation.setDuration(2500);
		
		AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
		alphaAnimation.setDuration(2500);
		
		ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_PARENT,0.67f, Animation.RELATIVE_TO_PARENT, 0.67f);
		scaleAnimation.setDuration(2500);
		
		TranslateAnimation translateAnimation = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, 0,  Animation.RELATIVE_TO_PARENT, 0.67f,  Animation.RELATIVE_TO_PARENT, 0,  Animation.RELATIVE_TO_PARENT, 0.67f);
		translateAnimation.setStartOffset(2500);
		translateAnimation.setDuration(2500);
		
		AnimationSet set = new AnimationSet(true);
		set.addAnimation(rotateAnimation);
		set.addAnimation(alphaAnimation);
		set.addAnimation(scaleAnimation);
		set.addAnimation(translateAnimation);
		view.startAnimation(set);
	}</span>

上面的程式碼還是很簡單的,想想如果位置從A平移到B,是應該以什麼樣的速率來移動呢,預設的是勻速了,所有你也可以指定或者自定義動畫過程中要用到的插值器,Interpolator插值器,用來定義動畫執行過程中的具體行為,變化速率。插值器也可以用在屬性動畫上。
	/**
	 *Interpolator插值器,用來定義動畫執行過程中的具體行為,變化速率 
	 *
	 *已經定義好了的插值器有這些
	 *AccelerateDecelerateInterpolator   在動畫開始與介紹的地方速率改變比較慢,在中間的時候加速
AccelerateInterpolator                     在動畫開始的地方速率改變比較慢,然後開始加速
AnticipateInterpolator                      開始的時候向後然後向前甩
AnticipateOvershootInterpolator     開始的時候向後然後向前甩一定值後返回最後的值
BounceInterpolator                          動畫結束的時候彈起
CycleInterpolator                             動畫迴圈播放特定的次數,速率改變沿著正弦曲線
DecelerateInterpolator                    在動畫開始的地方快然後慢
LinearInterpolator                            以常量速率改變
OvershootInterpolator                      向前甩一定值後再回到原來位置
	 */
應用插值器,
	public static void useSystemInterpolator(View view,Interpolator i){
		AnimationSet set = new AnimationSet(true);
		set.addAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.scale_anim));
		set.setInterpolator(i);
		view.startAnimation(set);
	}


3.屬性動畫,也可以用xml或者java定義。

涉及到2個類

ValueAnimator,這個本身不能對view造成動畫效果,它是根據指定屬性的起始值,可選指定插值器,新增監聽動畫回撥變化過程中的返回值,根據返回值來動態改變view的屬性值。
ObjectAnimator,物件動畫,直接作用於view
/**
 * 補間動畫雖能對控制元件做動畫,但並沒有改變控制元件內部的屬性值。 比如平移後,雖然外觀上位置看像移動了,其實是沒有移動
* 
 * 屬性動畫,ValueAnimator; 它本身不會對任何view做操作,需要我們監聽它的值變化,
* 在變化中自己改變view的值,從而實現動畫.至於這個區間的值變化是怎樣的,我們可以自己去
* 設定它的animator.setInterpolator(new BounceInterpolator());
 * 
 * 而和它的子類ObjectAnimator關聯了我們要動畫的物件,這樣子我們就不需要
* 每次監聽變化了
*/

xml定義,
    /**
     * xml檔案中定義屬性動畫
     * 標籤對應;
     * <value_animator />:對應ValueAnimator
     <objectAnimator />:對應ObjectAnimator
     <set />:對應AnimatorSet
     *
     * <value_animator
     android:duration="int"
     android:valueFrom="float | int | color"
     android:valueTo="float | int | color"
     android:startOffset="int"
     android:repeatCount="int"
     android:repeatMode=["repeat" | "reverse"]
     android:valueType=["intType" | "floatType"]
     android:interpolator=["@android:interpolator/XXX"]/>
     */
    public static void loadXmlAnimator(final View view){
//        ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(view.getContext(), R.animator.value_animator);
//        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                int offset = (int)animation.getAnimatedValue();
//                view.layout( offset,offset,view.getWidth()+offset,view.getHeight() + offset);
//            }
//        });
//        valueAnimator.start();

//        ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(view.getContext(), R.animator.object_animator);
//        objectAnimator.setTarget(view);
//        objectAnimator.start();

        AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(view.getContext(), R.animator.set_animator);
        set.setTarget(view);
        set.start();
    }
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="TranslationY"
    android:duration="2000"
    android:valueFrom="0.0"
    android:valueTo="400.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:valueType="floatType"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:startOffset="2000"/>

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="rotation"
    android:repeatCount="1"
    android:valueFrom="0"
    android:valueTo="360"
    android:valueType="floatType" >

</objectAnimator>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    <objectAnimator
        android:propertyName="x"
        android:duration="2500"
        android:valueFrom="0"
        android:valueTo="400"
        android:valueType="floatType"/>
    <objectAnimator
        android:propertyName="y"
        android:duration="2500"
        android:valueFrom="0"
        android:valueTo="300"
        android:valueType="floatType"/>
</set>

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:anim/bounce_interpolator"
    android:startOffset="2000"
    android:valueFrom="0"
    android:valueTo="300"
    android:valueType="intType" />




java中定義,
package com.example.customeviewserial.property_animation;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.example.customeviewserial.R;

/**
 * GroupFlexBoll提供一個例子說明用java程式碼建立屬性動畫
 *關鍵程式碼startTranslate()方法
 *  */
public class GroupFlexBoll extends RelativeLayout {
	private static final int[] BTN_RES = { R.drawable.home,
			R.drawable.iv1, R.drawable.iv2,
			R.drawable.iv3 };
	private static final int SWAP_ANGLE = 90;
	private static final int BOLLNUM = 3;
	private static final float SPACE_ANGLE = SWAP_ANGLE / (BOLLNUM - 1);
	RelativeLayout.LayoutParams params;
	private int radius;
	private ImageView homeImageView;
	private ImageView iv1;
	private ImageView iv2;
	private ImageView iv3;

	public GroupFlexBoll(Context context, AttributeSet attrs) {
		super(context, attrs);
		addView(context);
	}

	private void addView(Context context) {
		homeImageView = new ImageView(context);
		homeImageView.setTag("home");
		params = new RelativeLayout.LayoutParams(40, 40);
		params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		homeImageView.setImageResource(BTN_RES[0]);
		addView(homeImageView, params);

		iv1 = new ImageView(context);
		iv1.setImageResource(BTN_RES[1]);
		iv1.setTag("iv1");
		addView(iv1, params);

		iv2 = new ImageView(context);
		iv2.setImageResource(BTN_RES[2]);
		iv2.setTag("iv2");
		addView(iv2, params);

		iv3 = new ImageView(context);
		iv3.setImageResource(BTN_RES[3]);
		iv3.setTag("iv3");
		addView(iv3, params);

		setSubBtnVisible(false);
	}

	public void setOperationListener(OnClickListener l) {
		homeImageView.setOnClickListener(l);
		iv1.setOnClickListener(l);
		iv2.setOnClickListener(l);
		iv3.setOnClickListener(l);
	}

	private void setSubBtnVisible(boolean isVisible) {
		if (isVisible) {
			iv1.setVisibility(View.VISIBLE);
			iv2.setVisibility(View.VISIBLE);
			iv3.setVisibility(View.VISIBLE);
		} else {
			iv1.setVisibility(View.GONE);
			iv2.setVisibility(View.GONE);
			iv3.setVisibility(View.GONE);
		}
	}
	
	private void setSubBtnEnable(boolean isEnabled){
		if(isEnabled){
			iv1.setEnabled(true);
			iv2.setEnabled(true);
			iv3.setEnabled(true);
		}else{
			iv1.setEnabled(false);
			iv2.setEnabled(false);
			iv3.setEnabled(false);
		}
	}

	private boolean isOpend = false;
	private int boll_radius;

	public void toggle() {
		isOpend = !isOpend;
		doAnimation();
	}

	private void doAnimation() {
		setSubBtnVisible(true);
		startTranslate();
	}

	private void startTranslate() {
		int willTranslateLen = boll_radius * 2 * 3;
		ObjectAnimator animator1Y, animator2Y, animator3Y, animator1X, animator2X, animator3X;
		if (isOpend) {
			animator1Y = ObjectAnimator.ofFloat(iv1, "translationY", 0,
					-willTranslateLen);
			animator2Y = ObjectAnimator.ofFloat(iv2, "translationY", 0,
					(float) (-willTranslateLen * Math.cos(Math.toRadians(45))));
			animator3Y = ObjectAnimator.ofFloat(iv3, "translationY", 0, 0);

			animator1X = ObjectAnimator.ofFloat(iv1, "translationX", 0, 0);
			animator2X = ObjectAnimator.ofFloat(iv2, "translationX", 0,
					(float) (-willTranslateLen * Math.sin(Math.toRadians(45))));
			animator3X = ObjectAnimator.ofFloat(iv3, "translationX", 0,
					(float) (-willTranslateLen * Math.sin(Math.toRadians(90))));
		} else {
			animator1Y = ObjectAnimator.ofFloat(iv1, "translationY",
					-willTranslateLen, 0);
			animator2Y = ObjectAnimator.ofFloat(iv2, "translationY",
					(float) (-willTranslateLen * Math.cos(Math.toRadians(45))),
					0);
			animator3Y = ObjectAnimator.ofFloat(iv3, "translationY", 0, 0);

			animator1X = ObjectAnimator.ofFloat(iv1, "translationX", 0, 0);
			animator2X = ObjectAnimator.ofFloat(iv2, "translationX",
					(float) (-willTranslateLen * Math.sin(Math.toRadians(45))),
					0);
			animator3X = ObjectAnimator.ofFloat(iv3, "translationX",
					(float) (-willTranslateLen * Math.sin(Math.toRadians(90))),
					0);
		}

		Animator rotateAnimator1 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
		Animator rotateAnimator2 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
		Animator rotateAnimator3 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
		rotateAnimator1.setTarget(iv1);
		rotateAnimator2.setTarget(iv2);
		rotateAnimator3.setTarget(iv3);
		rotateAnimator1.setDuration(100);
		rotateAnimator2.setDuration(100);
		rotateAnimator3.setDuration(100);
		
		AnimatorSet set = new AnimatorSet();
		set.addListener(new AnimatorListener() {
			@Override
			public void onAnimationStart(Animator animation) {
				homeImageView.setEnabled(false);
				setSubBtnEnable(false);
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				if (isOpend == false) {
					setSubBtnVisible(false);
				}else{
					setSubBtnEnable(true);
				}
				homeImageView.setEnabled(true);
			}

			@Override
			public void onAnimationCancel(Animator animation) {
			}
		});
		set.playTogether(animator1Y, animator2Y, animator3Y, animator1X,
				animator2X, animator3X,rotateAnimator1,rotateAnimator2,rotateAnimator3);
		set.setDuration(1500);
		if(isOpend){
			set.setInterpolator(new BounceInterpolator());
		}else{
			set.setInterpolator(new AccelerateInterpolator());
		}
		set.start();
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			int measuredWidth = getMeasuredWidth();
			int measuredHeight = getMeasuredHeight();
			radius = Math.min(measuredWidth, measuredHeight);

			measureBtnSize();
		}
	}

	private void measureBtnSize() {
		params.width = radius / 4;
		params.height = radius / 4;

		boll_radius = radius / 8;

		homeImageView.setLayoutParams(params);
		iv1.setLayoutParams(params);
		iv2.setLayoutParams(params);
		iv3.setLayoutParams(params);
	}

}

控制動畫順序,
package com.example.customeviewserial.set_order_animator;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;

/**
 * Created by Administrator on 2016/5/24 0024.
 */
public class GuideUser {
    /**
     * AnimatorSet實現的屬性動畫集合,
     * 控制各個動畫的執行順序
     * playSequentially,playTogether
     */
    public static void startAnimatorSet(View... view){
        ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(view[0], "BackgroundColor",  0xffff00ff, 0xffffff00, 0xffff00ff);
        ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(view[1], "translationY", 0, 300, 0);
        ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(view[2], "translationY", 0, 400, 0);
        AnimatorSet animatorSet = new AnimatorSet();
//      animatorSet.playSequentially(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
        animatorSet.playTogether(tv1BgAnimator,tv1TranslateY,tv2TranslateY);

        //自由設定動畫順序——AnimatorSet.Builder
        AnimatorSet.Builder builder = animatorSet.play(tv1BgAnimator);
        /**
         * //和前面動畫一起執行
         public Builder with(Animator anim)
         //執行先執行這個動畫再執行前面動畫
         public Builder before(Animator anim)
         //執行前面的動畫後才執行該動畫
         public Builder after(Animator anim)
         //延遲n毫秒之後執行動畫
         public Builder after(long delay)
         */

//AnimatorSet沒有統一設定的情況下,各自按各自的來。這裡統一設定了時間,會覆蓋各自的時間
        animatorSet.setDuration(1000);

        animatorSet.start();
    }
}
4.viewgroup初始化,viewgroup中新增和移除子view時新增動畫;
涉及到LayoutTransition和之前提到的屬性動畫;
	/**
	 * 普通viewGroup新增進入統一動畫的LayoutAnimation
	 * 和針對grideView新增進入動畫的gridLayoutAnimation; 這2個類只能保證在建立的時候有動畫。
	 * 
	 * android:animateLayoutChanges==true可以為任何viewgroup控制元件加上預設動畫
	 * 和LayoutTransition則可以來自定義動畫
	 * 
	 * 1.可以在xml檔案中指定
	 * 在anim資料夾中定義<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/slide_in_left"
    android:animationOrder="normal"
    android:delay="1" />
    delay值是animation時間值的倍數
    animation引用的只能是animation動畫,不能是animator
    
    定義好後,在layout中引用  android:layoutAnimation="@anim/layout_animation"
    動畫只在第一次建立容器的時候有動畫
    android:animationOrder指viewGroup中的控制元件動畫開始順序,取值有normal(正序)、reverse(倒序)、random(隨機)
    
    
    2.可以在Java檔案中指定
    //程式碼設定通過載入XML動畫設定檔案來建立一個Animation物件;
        Animation animation= AnimationUtils.loadAnimation(this,R.anim.slide_in_left);   //得到一個LayoutAnimationController物件;
        LayoutAnimationController controller = new LayoutAnimationController(animation);   //設定控制元件顯示的順序;
        controller.setOrder(LayoutAnimationController.ORDER_REVERSE);   //設定控制元件顯示間隔時間;
        controller.setDelay(0.3f);   //為ListView設定LayoutAnimationController屬性;
        mListView.setLayoutAnimation(controller);
        mListView.startLayoutAnimation();
        
        
        對應的GridView:
        Animation animation = AnimationUtils.loadAnimation(MyActivity.this,R.anim.slide_in_left);
        GridLayoutAnimationController controller = new GridLayoutAnimationController(animation);
        controller.setColumnDelay(0.75f);
        controller.setRowDelay(0.5f);
        controller.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP|GridLayoutAnimationController.DIRECTION_LEFT_TO_RIGHT);
        controller.setDirectionPriority(GridLayoutAnimationController.PRIORITY_NONE);
        grid.setLayoutAnimation(controller);
        grid.startLayoutAnimation();
        
        
        
        3.LayoutTransition則可以來為viewgroup自定義新增屬性動畫
        LayoutTransaction transitioner = new LayoutTransition();  
        ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);  
		transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
		linearLayout.setLayoutTransition(mTransitioner); 
		
		第一個引數int transitionType:表示當前應用動畫的物件範圍,取值有:
APPEARING —— 元素在容器中出現時所定義的動畫。
DISAPPEARING —— 元素在容器中消失時所定義的動畫。
CHANGE_APPEARING —— 由於容器中要顯現一個新的元素,其它需要變化的元素所應用的動畫
CHANGE_DISAPPEARING —— 當容器中某個元素消失,其它需要變化的元素所應用的動畫
	 */


/**
	 * 測試LayoutTransition效果
	 * 這裡有幾點注意事項: 
1、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder所構造的動畫才會有效果,不然無效!也就是說使用ObjectAnimator構造的動畫,在這裡是不會有效果的! 
2、在構造PropertyValuesHolder動畫時,”left”、”top”屬性的變動是必寫的。如果不需要變動,則直接寫為:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);  
3、在構造PropertyValuesHolder時,所使用的ofInt,ofFloat中的引數值,第一個值和最後一個值必須相同,不然此屬性所對應的的動畫將被放棄,在此屬性值上將不會有效果;
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
比如,這裡ofInt(“left”,0,100,0)第一個值和最後一個值都是0,所以這裡會有效果的,如果我們改為ofInt(“left”,0,100);那麼由於首尾值不一致,則將被視為無效引數,將不會有效果! 
4、在構造PropertyValuesHolder時,所使用的ofInt,ofFloat中,如果所有引數值都相同,也將不會有動畫效果。 
比如
	 */

下面是一個具體例子,
	/**
	 *為viewgroup應用LayoutTransition動畫
	 */
	private void useLayoutTransition() {
		LayoutTransition layoutTransition = new LayoutTransition();
		boolean checked = radio_appear.isChecked();
		boolean checked2 = radio_disappear.isChecked();
		boolean checked3 = radio_change_appear.isChecked();
		boolean checked4 = radio_change_disappear.isChecked();
		if (checked || checked2 || checked3 || checked4) {
		} else {
			return;
		}

		if (checked) { // 自身動畫新增
			ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null,
					"alpha", 0, 1);
			layoutTransition.setAnimator(LayoutTransition.APPEARING,
					appearAnimator);
		}

		if (checked2) { // 自身移除動畫
			ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null,
					"alpha", 1, 0);
			layoutTransition.setAnimator(LayoutTransition.DISAPPEARING,
					disappearAnimator);
		}

		if (checked3) { // 自身新增時對其他控制元件應用的動畫
			PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",
					0, 100, 0);
			PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0,
					0);
			Animator changeAppearAnimator = ObjectAnimator
					.ofPropertyValuesHolder(layout, pvhLeft, pvhTop);
			layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING,
					changeAppearAnimator);
		}

		if (checked4) { // 自身移除時對其他控制元件應用的動畫
			PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",
					0, 0);
			PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0,
					0);
			PropertyValuesHolder pvhRotateX = PropertyValuesHolder.ofFloat(
					"rotationX", 0,180, 0);
			Animator changeDisAppearAnimator = ObjectAnimator
					.ofPropertyValuesHolder(layout, pvhLeft, pvhTop,
							pvhRotateX);
			layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
					changeDisAppearAnimator);
		}
		layoutTransition.setDuration(1000);
//		layoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 500);
		layoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 100);
		layoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 100);//其他條目動畫時的間隔
		layout.setLayoutTransition(layoutTransition);
	}


5.在activity和fragment進入和退出時運用動畫。這些動畫都是對activity或者fragment整體的所有佈局元素統一進行相同的動畫。
activity的進入和退出的動畫,我們可以使用程式碼中應用:
在startActivity或者finish之後呼叫overridePendingTransition(int enterAnim,int exitAnim);
這裡的動畫id是xml中定義的檢視動畫,enterAnim是進入的那個activity的動畫,exitAnim是退出的那個activity的動畫。
還有一種方法是使用主題的方式為application或者activity指定主題,例如,
定義主題:
<style name="FeelyouWindowAnimTheme" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/in_from_left</item>
        <item name="android:activityOpenExitAnimation">@anim/out_from_right</item>
        <item name="android:activityCloseEnterAnimation">@anim/in_from_right</item>
        <item name="android:activityCloseExitAnimation">@anim/out_from_left</item>
    </style>
    <style name="AnimActivityTheme">
        <item name="android:windowAnimationStyle">@style/FeelyouWindowAnimTheme</item>
    </style>

res/anim/下定義一些檢視動畫:
in_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="100%p"
        android:toXDelta="0" />
</set>

in_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />
</set>

out_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:toXDelta="100%p" />
</set>
out_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />
</set>
應用主題:
  <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AnimActivityTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Main2Activity"></activity>
    </application>

fragment的進入和退出動畫如下:

請使用v4包下的Fragment保證相容,在fragmentTransition提交之前應用動畫就行;

  if (null == mFragmentManager) {
                    mFragmentManager = getSupportFragmentManager();
                }

                fragment = new BlankFragment();
                FragmentTransaction fragmentTransaction = mFragmentManager
                        .beginTransaction();
                fragmentTransaction.setCustomAnimations(
                        R.anim.in_from_left,
                        R.anim.out_from_right,
                        R.anim.in_from_right,
                        R.anim.out_from_left);

                fragmentTransaction.add(R.id.container, fragment);

                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();


6.android5.0為我們提供了一種針對activity或者fragment切換過渡時的新動畫,不像上面的過渡動畫是針對整個的佈局元素執行的是同一個動畫,android5.0的過渡動畫更加豐富,可以針對其中的共享某些元素執行動畫。可以根據原理自己寫效果了。

提供了三種Transition型別:

進入:一個進入的過渡(動畫)決定activity中的所有的檢視怎麼進入螢幕。
退出:一個退出的過渡(動畫)決定一個activity中的所有檢視怎麼退出螢幕。

共享元素:一個共享元素過渡(動畫)決定兩個activities之間的過渡,怎麼共享(它們)的檢視。

</pre><p><pre name="code" class="java"> Transition過渡可以在xml檔案中定義或者Java程式碼建立對應的類,例如在res/transition資料夾下定義它的節點可以是Transition的子類,
 	ChangeBounds
 	ChangeClipBounds
 	ChangeImageTransform
 	ChangeTransform
 	TransitionSet
 	Explode
 	Fade
 	Slide
 TransitionInflater提供將xml中定義的transition轉為transition物件
 TransitionManager管理Scene和Transition
 TransitionDrawable實現drawable有過渡效果

changeBounds -  改變目標檢視的佈局邊界

changeClipBounds - 裁剪目標檢視邊界

changeTransform - 改變目標檢視的縮放比例和旋轉角度

changeImageTransform - 改變目標圖片的大小和縮放比例

過渡動畫的執行時機;並且傳入一個你想要執行的動畫

Window.setEnterTransition():設定進入動畫

Window.setExitTransition():設定退出效果

Window.setSharedElementEnterTransition():設定共享元素的進入動畫

Window.setSharedElementExitTransition():設定共享元素的退出動畫

具體使用:

/ /允許使用transitions  

getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);  

//設定一個transition

getWindow().setExitTransition(new Explode());//new Slide()  new Fade() ;

//跳轉

startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

為共享元素執行過渡動畫時,有點不同:

使用android:transitionName屬性給兩個佈局中的共享元素指定一個相同的名字(名字一定不要寫錯)

然後執行:startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,view,"shareName").toBundle()); 

如果有多個共享元素使用:

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,  

        Pair.create(view1, "agreedName1"),  

        Pair.create(view2, "agreedName2")); 

退出要使用:在程式碼中觸發通過finishAfterTransition()方法觸發返回動畫,而不是呼叫finish()方法.

7.Scene的使用: api19開始才有的特性,Scene場景,常見使用方法,  public Scene(ViewGroup sceneRoot, View layout)  public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)  Transition過渡,內部包含場景轉換時的動畫。可能對SurfaceView,TextureView不起作用。 工作原理是,捕捉兩個Scene的狀態,根據這2個狀態的區別建立屬性動畫Animator.實際上是對屬性動畫的一個應用,使用更簡單的api實現 了複雜的功能。 這些優點將使得我們只用少量程式碼就可以建立複雜的Activity和Fragment切換動畫

使用步驟:

應用scene transition 場景轉換 1.建立transition 從xml中Transition mFadeTransition =        TransitionInflater.from(this).        inflateTransition(R.transition.fade_transition);從java中建立,Transition mFadeTransition = new Fade();2.使用TransitionManager.go(mEndingScene, mFadeTransition);

res/transition/fade_transition.xml

<?xml version="1.0" encoding="utf-8"?><fade xmlns:android="http://schemas.android.com/apk/res/android" />

例子:

package com.example.androidtest;

import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.os.Bundle;
import android.transition.AutoTransition;
import android.transition.Scene;
import android.transition.TransitionManager;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;

@TargetApi(Build.VERSION_CODES.KITKAT)
public class MainActivity extends Activity {

	private AutoTransition transition;
	private Scene scene1;
	private Scene scene2;
	private boolean start;
	private ImageView iv;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.start_layout);
		iv = (ImageView)findViewById(R.id.iv);
		
		// get the root layout ID
		RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.base);
		
		//場景的定義,首先根佈局要一樣且定義id;每個場景中具有相同id的視為同一個view實現過渡效果,不同的id則只是簡單的漸隱漸顯
		scene1 = Scene.getSceneForLayout(rootLayout, R.layout.start_layout,this);
		scene2 = Scene.getSceneForLayout(rootLayout, R.layout.end_layout, this);
		
		// create transition, set properties
		//程式碼建立過渡,也可以使用xml中定義過渡,再使用TransitionInflater.from(this).inflateTransition(resource)解析
		transition = new AutoTransition();
		transition.setDuration(2000);
		transition.setInterpolator(new AccelerateDecelerateInterpolator());
		// initialize flag
		start = true;
	}
	
	/**
	 * 下面幾個效果需要api21
	 * ChangeBounds
 	ChangeClipBounds
 	ChangeImageTransform
 	ChangeTransform
 	TransitionSet
 	
 	Explode
 	Fade
 	Slide
	 * @param v
	 */

	public void changeScene(View v) {
		// check flag
		if (start) {
			TransitionManager.go(scene2, transition);
			start = false;
		} else {
			TransitionManager.go(scene1, transition);
			start = true;
		}
		
		//TransitionDrawable是針對圖片之間的過渡
		TransitionDrawable drawable = (TransitionDrawable) iv.getBackground();
		drawable.startTransition(2000);
	}

}
start_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/base"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff000000"
    tools:context=".TransitionsActivity" >

    <ImageView
        android:id="@+id/iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:background="@drawable/transitiondrawable" />

    <ImageButton
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape1" />

    <ImageButton
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape2" />

    <ImageButton
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape3" />

    <ImageButton
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape4" />

</RelativeLayout>

end_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#ff000000" 
    android:id="@+id/base" 
    tools:context=".TransitionsActivity"> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn1" 
        android:src="@drawable/shape1" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentRight="true" 
        android:layout_alignParentBottom="true" 
        android:onClick="changeScene"/> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn2" 
        android:src="@drawable/shape2" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentLeft="true" 
        android:layout_alignParentBottom="true" 
        android:onClick="changeScene"/> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn3" 
        android:src="@drawable/shape3" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentRight="true" 
        android:layout_alignParentTop="true" 
        android:onClick="changeScene"/> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn4" 
        android:src="@drawable/shape4" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentLeft="true" 
        android:layout_alignParentTop="true" 
        android:onClick="changeScene"/> 

</RelativeLayout>

res/drawable/transitiondrawable.xml
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@drawable/shape1">
    </item>
    <item android:drawable="@drawable/shape2">
    </item>

</transition>