Android開發之tween(補間動畫)動畫及其使用場景(界面切換、彈窗等)詳解

在Android開發中,我們常見一些很絢麗的動畫效果。這些動畫效果使得我們的應用用起來非常的絢麗。那麼今天就來講講Android開發中,常用的動畫效果吧。


在Android開發中,有幀動畫和補間動畫兩種

1、逐幀動畫是在時間幀上逐幀繪製幀內容,由於是一幀一幀的畫,所以逐幀動畫具有非常大的靈活性,幾乎可以表現任何想表現的內容。但是在開發中,我們不常用這個動畫。

2、與逐幀動畫相比,補間動畫具有以下幾個特點:首先,製作方法簡單方便。只需要爲動畫的第一個關鍵幀和最後一個關鍵幀創建內容,兩個關鍵幀之間幀的內容由Flash自動生成,不需要人爲處理。其次,相對於逐幀動畫來說,補間動畫更爲連貫自然。因爲逐幀動畫是由手工控制,幀與幀之間的過渡很可能會不自然、不連貫,而補間動畫除了兩個關鍵幀由手工控制外,中間的幀都由Flash自動生成,技術含量很高,因此過渡更爲自然連貫。最後,相對於逐幀動畫來說,補間動畫的文件更小,佔用內存少。


今天,我們詳細的講解補間動畫。所謂補間動畫,就是在兩個畫面跳轉的時候,執行的動畫。在Android開發中,我們在activity切換,fragment切換,dialog、PopupWindow以及使用WindowManager的時候,我們都會有需要動畫來是的切換或者展示效果更佳的絢麗。補間動畫有四種:平移、縮放、旋轉、漸變。


一、在代碼中實現動畫效果,這裏博主自定義了一個Animation提供者,直接上代碼:

/**
 * @ClassName: FreedomAnimationUtils
 * @author victor_freedom ([email protected])
 * @createddate 2014年12月22日 下午9:57:21
 * @Description: 動畫工具提供者
 */
public class FreedomAnimationUtils {

	/**
	 * @Title: getRotateAnimation
	 * @Description: 旋轉動畫
	 * @param fromDegrees
	 *            起始角度
	 * @param toDegrees
	 *            結束角度
	 * @param pivotXType
	 *            相對於什麼位置(Animation.RELATIVE_TO_SELF(相對於父控件),
	 *            Animation.RELATIVE_TO_SELF(相對於自己),Animation.ABSOLUTE(絕對位置))
	 * @param pivotXValue
	 *            以什麼爲中心點
	 * @param pivotYType
	 *            同上
	 * @param pivotYValue
	 *            同上
	 * @param durationMillis
	 *            維持時間
	 * @return
	 * @throws
	 */
	public static Animation getRotateAnimation(float fromDegrees,
			float toDegrees, int pivotXType, float pivotXValue, int pivotYType,
			float pivotYValue, long durationMillis) {
		RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		// 重複模式:1、重新開始;2、從尾開始
		rotate.setRepeatMode(Animation.RESTART);
		rotate.setRepeatMode(Animation.REVERSE);
		// 維持時間
		rotate.setDuration(durationMillis);
		// 完畢之後是否保持狀態
		rotate.setFillAfter(true);
		return rotate;
	}

	/**
	 * @Title: getAlphaAnimation
	 * @Description: 透明度
	 * @param fromAlpha
	 * @param toAlpha
	 * @param durationMillis
	 * @return
	 * @throws
	 */
	public static Animation getAlphaAnimation(float fromAlpha, float toAlpha,
			long durationMillis) {
		AlphaAnimation alpha = new AlphaAnimation(fromAlpha, toAlpha);
		// 重複次數
		alpha.setRepeatCount(2);
		// 重複模式:1、重新開始;2、從尾開始
		alpha.setRepeatMode(Animation.RESTART);
		alpha.setRepeatMode(Animation.REVERSE);
		// 維持時間
		alpha.setDuration(durationMillis);
		// 完畢之後是否保持狀態
		alpha.setFillAfter(true);
		return alpha;
	}

	/**
	 * @Title: getScaleAnimation
	 * @Description: 縮放動畫
	 * @param fromX
	 *            起始大小
	 * @param toX
	 *            縮放後大小
	 * @param fromY
	 *            起始大小
	 * @param toY
	 *            縮放後大小
	 * @param pivotXType
	 *            縮放參照物,相對於哪一個位置(Animation.ABSOLUTE,
	 *            Animation.RELATIVE_TO_SELF,or Animation.RELATIVE_TO_PARENT);
	 * @param pivotXValue
	 *            縮放的時候以哪一個位置爲中心點,一般寫0.5f,相對於控件中央
	 * @param pivotYType
	 * @param pivotYValue
	 * @param durationMillis
	 * @return
	 * @throws
	 */
	public static Animation getScaleAnimation(float fromX, float toX,
			float fromY, float toY, int pivotXType, float pivotXValue,
			int pivotYType, float pivotYValue, long durationMillis) {
		ScaleAnimation scale = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		scale.setDuration(durationMillis);
		return scale;
	}

	/**
	 * @Title: getTranslateAnimation
	 * @Description: TODO
	 * @param fromXDelta
	 *            這個參數表示動畫開始的點離當前View X座標上的差值;
	 * @param toXDelta
	 *            這個參數表示動畫結束的點離當前View X座標上的差值;
	 * @param fromYDelta
	 *            這個參數表示動畫開始的點離當前View Y座標上的差值;
	 * @param toYDelta
	 *            這個參數表示動畫開始的點離當前View Y座標上的差值;
	 * @param durationMillis
	 * @return
	 * @throws
	 */
	public static Animation getTranslateAnimation(float fromXDelta,
			float toXDelta, float fromYDelta, float toYDelta,
			long durationMillis) {
		TranslateAnimation translate = new TranslateAnimation(fromXDelta,
				toXDelta, fromYDelta, toYDelta);
		translate.setDuration(durationMillis);
		translate.setFillAfter(true);
		return translate;
	}

	/**
	 * @Title: getTranslateAnimations
	 * @Description: TODO
	 * @param fromXType
	 *            第一個參數是x軸方向的值的參照(Animation.ABSOLUTE,
	 *            Animation.RELATIVE_TO_SELF,or Animation.RELATIVE_TO_PARENT);
	 * @param fromXValue
	 *            第二個參數是第一個參數類型的起始值;
	 * @param toXType
	 *            第三個參數與第四個參數是x軸方向的終點參照與對應值
	 * @param toXValue
	 *            結束位置的值
	 * @param fromYType
	 * @param fromYValue
	 * @param toYType
	 * @param toYValue
	 * @param durationMillis
	 * @return
	 * @throws
	 */
	public static Animation getTranslateAnimations(int fromXType,
			float fromXValue, int toXType, float toXValue, int fromYType,
			float fromYValue, int toYType, float toYValue, long durationMillis) {
		TranslateAnimation translate = new TranslateAnimation(fromXType,
				fromXValue, toXType, toXValue, fromYType, fromYValue, toYType,
				toYValue);
		translate.setDuration(durationMillis);
		translate.setFillAfter(false);
		return translate;
	}

	/**
	 * @Title: getAnimationSet
	 * @Description: 組合動畫
	 * @return
	 * @throws
	 */
	public static AnimationSet getAnimationSet() {
		// 頂一個一個set
		AnimationSet animationSet = new AnimationSet(false);
		ScaleAnimation sa = new ScaleAnimation(0.2f, 2.0f, 0.2f, 2.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
				0.5f);
		sa.setDuration(2000);
		sa.setRepeatCount(2);
		sa.setRepeatMode(Animation.REVERSE);

		RotateAnimation ra = new RotateAnimation(0, 360,
				Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
				1.0f);
		ra.setDuration(2000);
		ra.setRepeatCount(2);
		ra.setRepeatMode(Animation.REVERSE);

		TranslateAnimation ta = new TranslateAnimation(
				Animation.RELATIVE_TO_PARENT, 0.0f,
				Animation.RELATIVE_TO_PARENT, 1.0f,
				Animation.RELATIVE_TO_PARENT, 0.0f,
				Animation.RELATIVE_TO_PARENT, 1.0f);

		ta.setDuration(2000);
		ta.setRepeatCount(2);
		ta.setRepeatMode(Animation.REVERSE);
		// 將定義好的動畫直接加入到set中
		animationSet.addAnimation(sa);
		animationSet.addAnimation(ra);
		animationSet.addAnimation(ta);
		return animationSet;
	}

}

二、在XML文件中自定義動畫

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

    <!--
    %:相對於view自身位置移動,相當於Animation.RELATIVE_TO_SELF
    %p:相對於父元素,參考的是父元素,相當於Animation.RELATIVE_TO_PARENT
	什麼都不寫相當於Animation.ABSOLUTE
	
	其中interpolator是一個函數計算過程,是動畫播放過程中的變化率
	Android提供的幾個定義好的類直接使用,有興趣的朋友也可以自己去自定義變化率
	AccelerateDecelerateInterpolator        在動畫開始與介紹的地方速率改變比較慢,在中間的時侯加速
	AccelerateInterpolator        在動畫開始的地方速率改變比較慢,然後開始加速	
	CycleInterpolator        動畫循環播放特定的次數,速率改變沿着正弦曲線
	DecelerateInterpolator        在動畫開始的地方速率改變比較慢,然後開始減速
	LinearInterpolator        在動畫的以均勻的速率改變

    -->

    <scale
        android:duration="200"
        android:fillAfter="false"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="2"
        android:repeatMode="restart"
        android:toXScale="1.0"
        android:toYScale="1.0" />

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

    <translate
        android:fillAfter="true"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:repeatCount="2"
        android:repeatMode="restart"
        android:toXDelta="100%"
        android:toYDelta="100%" />

    <rotate
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="2"
        android:repeatMode="restart"
        android:toDegrees="100" />

</set>

調用XML編寫的動畫只需要寫Animation animation = AnimationUtils.loadAnimation(this,R.anim.xxx);即可

三、Anctivity切換動畫:

對於Activity切換動畫,我們只需要在startActivity之後,加上一句即可:

Intent intent=new Intent(PathButtonActivity.this,MainActivity.class);  
            startActivity(intent);  
            //第一個參數爲啓動時動畫效果,第二個參數爲退出時動畫效果  
            overridePendingTransition(R.anim.fade, R.anim.hold); 


四、Fragment切換動畫

在使用fragment切換動畫的時候要特別注意,如果你的fragment不是V4包的fragment,那麼使用切換的動畫資源必須放置在res\animator的目錄下,且根標籤是<set><objectAnimator><valueAnimator>之一,至於爲什麼,有興趣的朋友可以去研究一下Property Animation和View  Animation的區別。因爲我們常用的fragment肯定是包含V4包的,兼容性比較好,所以,我們只講在anim文件夾下的動畫使用。看代碼:

FragmentTransaction fragmentTransaction = mFragmentManager
                .beginTransaction();
        fragmentTransaction.setCustomAnimations(
                R.anim.push_left_in,
                R.anim.push_left_out,
                R.anim.push_left_in,
                R.anim.push_left_out);

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

在切換fragment使用動畫的時候,必須在add或者replace之前調用setCustomAnimations()方法。


五、Dialog、PopupWindow以及WindowManager彈窗動畫效果

這三者的實現動畫效果方式,其實是差不多的,都需要先定義一個風格style,看代碼:

  <style name="freedom_anim_style">
        <item name="android:windowEnterAnimation">@anim/popshow_anim</item> <!-- 指定顯示的動畫xml -->
        <item name="android:windowExitAnimation">@anim/pophidden_anim</item> <!-- 指定消失的動畫xml -->
    </style>

有了這個風格style之後,就方便很多了

1、Dialog實現彈出動畫:

AlertDialog.Builder b = new Builder(this);
		b.create().getWindow().setWindowAnimations(R.style.freedom_anim_style);

2、PopupWindow實現彈出動畫:

	PopupWindow p = new PopupWindow();
		p.setAnimationStyle(R.style.freedom_anim_style);

3、WindowManger添加窗體實現彈出動畫:(這個稍微多幾步,但是其實原理和之前兩個彈窗的底層是一樣的)我們以添加一個view爲例子

	view = View.inflate(context, R.layout.freedom, null);

		WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
				LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
				WindowManager.LayoutParams.TYPE_APPLICATION,
				WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
						| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, // 沒有邊界
				PixelFormat.TRANSLUCENT);
		lp.gravity = Gravity.TOP;
		// 重要 這就是添加動畫的地方
		lp.windowAnimations = R.style.freedom_anim_style;
		  WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
		wm.addView(view, lp);

到此Android開發中常用的動畫以及使用場景方式已經講解完畢,希望能夠幫助到看到此篇文章的人。









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