Android動畫之二:View Animation

做爲一個博客《Android其中的動畫:Drawable Animation》。android動畫主要分爲三大部分。上一篇博客已經解說Drawable Animation的使用方法,即逐幀地顯示圖片,經常運用於動態顯示一個進度動畫,這是出現頻率最高的應用場景。接下來。咱們這篇文章將按部就班。介紹View Animation。html

View Animation也是咱們平時很是多書籍所說的Tweened Animation(有人翻譯爲補間動畫)。View Animation分爲4大類:AlphaAnimation,RotateAnimation,ScaleAnimation,TranslateAnimation,分別相應透明度。旋轉,大小,位移四種變化。java

View Animation的效果由四個因素決定:1)初始狀態。2)結束狀態;3)持續時間;4)Interpolatorandroid

因此要定義一個View Animation,你僅僅要定義以上四個因素,中間的過程怎麼變化則有系統本身主動計算出來。windows

當中前3個因素很是easy理解,第四個因素Interpolator比較特別,這個單詞不知道怎麼翻譯比較適合。很是多書籍的翻譯都很是奇怪。Interpolator是決定動畫進行過程的速度變化。比方:你將一個button從屏幕左側運動到屏幕右側。可以讓它一直加速前進。或者先減速而後減速。這就是Interpolator發揮的做用,詳細用法如下會說,先從簡單的提及。app

像Drawable Animation同樣,定義一個View Animation可以用代碼的方式,也可以用XML文件的方式。咱們先來寫一個最簡單的樣例,對一個helloworld字符串進行移動。旋轉。放大。變暗。分別用代碼實現和XML文件實現。ide

先用代碼實現。佈局

首先新建project:ViewAnimationDemo,並新建一個佈局文件:animationjavacode.xml,例如如下:動畫

ViewAnimationDemo\res\layout\animationjavacode.xml
ui

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/translation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="50dp"
        android:text="我要移動" />

    <TextView
        android:id="@+id/rotate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/translation"
        android:layout_marginBottom="50dp"
        android:text="我要旋轉" />

    <TextView
        android:id="@+id/scale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/rotate"
        android:layout_marginBottom="50dp"
        android:text="我要變大" />

    <TextView
        android:id="@+id/alpha"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/scale"
        android:layout_marginBottom="200dp"
        android:text="我要變暗" />

    <Button
        android:id="@+id/fire"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_below="@id/alpha"
        android:text="運動" />

</RelativeLayout>

該XML佈局文件相應的Activity例如如下:

ViewAnimationDemo/src/com/CSDN/viewanimationdemo/AnimCodeActivity.java
this

public class AnimCodeActivity extends Activity {

	private TextView translation;
	private TextView rotate;
	private TextView scale;
	private TextView alpha;
	
	private Button button;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.animationjavacode);
        
        translation = (TextView) findViewById(R.id.translation);
        rotate = (TextView) findViewById(R.id.rotate);
        scale = (TextView) findViewById(R.id.scale);
        alpha = (TextView) findViewById(R.id.alpha);
        button = (Button) findViewById(R.id.fire);
        
        button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 1&2: 肯定起始狀態,結束狀態
				TranslateAnimation tAnim = new TranslateAnimation(0, 400, 0, 0);//橫向位移400個單位
				RotateAnimation rAnima = new RotateAnimation(0, 70);//順時針旋轉70度
				ScaleAnimation sAnima = new ScaleAnimation(0, 5, 0, 5);//橫向放大5倍,縱向放大5倍
				AlphaAnimation aAnima = new AlphaAnimation(1.0f, 0.0f);//從全不透明變爲全透明
				// 3: 肯定持續時間
				tAnim.setDuration(2000);
				rAnima.setDuration(2000);
				sAnima.setDuration(2000);
				aAnima.setDuration(2000);

				// 4: 肯定Interpolator
				tAnim.setInterpolator(new AccelerateDecelerateInterpolator());
				
				// 啓動動畫
				translation.startAnimation(tAnim);
				rotate.startAnimation(rAnima);
				scale.startAnimation(sAnima);
				alpha.startAnimation(aAnima);	
			}
		});
        
    }

}

從代碼中不難看到,首先肯定了動畫的起始狀態和結束狀態,而後經過setDuration(2000)設置持續時間,假設這裏不設置持續時間,將默以爲30mx。基本肉眼看不到。最後咱們設置了一個Interpolator,此處設置效果是動畫先減速進行,而後減速。

默認狀態時勻速進行。

沒錯。Interpolator的基本使用方法就是這麼easy。以上代碼效果圖例如如下:


接下來解說怎麼用xml定義動畫,依照android官網的介紹,定義View Animation的xml文件格式例如如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

該文件僅僅能有一個根結點,可以是<set>,<alpha>,<scale>,<translate>,<rotate>,而當中,<set>結點可以包括子節點,即可以包括<set>,<alpha>,<scale>,<translate>,<rotate>,以此類推。

以上需要解說的兩個標籤屬性是android:interpolator和android:shareInterpolator。前者表明你所使用的interpolator。可以是系統自帶,也可以是本身定義。

然後者表明,是否將該Interpolator共享給子節點。其餘子標籤的屬性很是easy理解,基本看屬性名字就能懂。除了當中兩個,android:pivotX和android:pivotY,咱們知道,pivot的意思是軸心的意思,因此這兩個屬性定義的是這次動畫變化的軸心位置,默認是左上角,當咱們把它們二者都賦值爲50%,則變化軸心在中心。

接下來寫一個詳細的樣例,例如如下,仍是在剛纔的項目中進行。通常咱們把定義動畫的xml文件放在res/anim文件夾下,首先咱們新建一個anim文件夾。而後新建一個xml文件,例如如下:

ViewAnimationDemo/res/anim/myanim.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <scale
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.4"
        android:fromYScale="1.0"
        android:toYScale="0.6"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false"
        android:duration="1000" />
    <set
        android:interpolator="@android:anim/accelerate_interpolator"
        android:startOffset="1000">
        <scale
            android:fromXScale="1.4"
            android:toXScale="0.0"
            android:fromYScale="0.6"
            android:toYScale="0.0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:duration="400" />
        <rotate
            android:fromDegrees="0"
            android:toDegrees="60"
            android:toYScale="0.0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:duration="400" />
    </set>
</set>

上述樣例的效果圖例如如下:


上面代碼中。有 惟一一個根節點<set>,它有兩個子節點<scale>和<set>,而後當中的子節點<set>擁有兩個本身的子節點<scale>和<rotate>。

解說一下上面一些沒見過的標籤屬性。

andoird:fillAfter:前面一個樣例中,咱們的動畫結束後helloworld又回到了原來狀態,經過設置fillAfter爲true,則動畫將保持結束的狀態。但是。如前一篇博客《Android動畫之中的一個:Drawable Animation》所說,View Animation的動畫效果是繪製出來的,並非該組件真正移動了,這個問題咱們興許會繼續探討。

現在僅僅需要知道將fillAfter設置爲true以後。動畫將保持結束狀態,這大多應用於設計連續發生的動畫。

startOffset:該屬性定義動畫推遲多久開始,經過這個屬性的設置,咱們可以設計一些先後按序發生的動畫,固然,除了最後一個發生的動畫,其它動畫得設置fillAfter爲true.

interpolator:這裏咱們使用了系統自帶的interpolator

接下來咱們定義一個佈局文件,該佈局文件僅僅有一張圖片。一個button,經過點擊button觸發圖片進行動畫,該佈局文件比較簡單,這裏不列出。怎樣在該佈局文件相應的activity代碼中啓動動畫呢,代碼例如如下:

ViewAnimationDemo/src/com/CSDN/viewanimationdemo/AnimaXmlActivity.java

public class AnimaXmlActivity extends Activity {

	private Button btn;
	private ImageView img;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_anima_xml);
		btn = (Button)findViewById(R.id.xml_btn);
		img = (ImageView)findViewById(R.id.xmlAnimImg);
		
		btn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Animation anim = AnimationUtils.loadAnimation(AnimaXmlActivity.this, R.anim.myanim);
				img.startAnimation(anim);
			}
		});
	}
}

以上代碼很是easy理解。咱們通常使用AnimationUtils讀取定義在xml文件裏的動畫。

到此爲止,關於View Animation的基礎知識基本已經覆蓋了。接下來寫一個詳細實踐的樣例,實現經常見到的側滑功能,如網易新聞這樣的:



這個側滑的效果實現並不難。很是多人運用了AsyncTask線程,但是結果你會發現有時會發生明顯的卡頓,但是假設使用動畫效果將會平滑很是多。咱們接下來實現這種功能:

首先新建一個項目:SwipeWithAnim。

並新建一個佈局文件activity_main.xml。例如如下

SwipeWithAnim/res/layout/activity_main.xml

<FrameLayout 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"
    tools:context=".MainActivity" >

    <View
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#e23451" />

    <LinearLayout
        android:id="@+id/menu"
        android:layout_width="400dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:layout_marginLeft="-380dp"
        android:orientation="horizontal" >

        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#eeeee1" />

        <View
            android:id="@+id/dragArea"
            android:layout_width="20dp"
            android:layout_height="match_parent"
            android:background="#00000000" />
    </LinearLayout>

</FrameLayout>

屏幕顯示內容content。左側隱去菜單menu,知識將20dp的透明部分放在屏幕左側,用於觸發onTouch事件。該xml文件相應的activity代碼例如如下:

SwipeWithAnim/src/com/CSDN/swipewithanim/MainActivity.java


public class MainActivity extends Activity {

	private View menu;
	private final static int SHOW_MENU = 1;
	private final static int HIDE_MENU = -1;
	private int swipe_tag = SHOW_MENU;
	private int max_menu_margin = 0;
	private int min_menu_margin;
	private float beginX;
	private float latestX;
	private float diffX;
	private float latestMargin;

	private FrameLayout.LayoutParams lp;

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);

		menu = findViewById(R.id.menu);
		lp = (FrameLayout.LayoutParams) menu.getLayoutParams();
		min_menu_margin = lp.leftMargin;

		menu.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				int action = MotionEventCompat.getActionMasked(event);
				switch (action) {
				case MotionEvent.ACTION_DOWN:
					beginX = event.getX();
					break;
				case MotionEvent.ACTION_MOVE:
					latestX = event.getX();
					diffX = latestX - beginX;
					swipe_tag = diffX > 0 ?

SHOW_MENU : HIDE_MENU; latestMargin = lp.leftMargin + diffX; if (latestMargin > min_menu_margin && latestMargin < max_menu_margin) { lp.leftMargin = (int) (latestMargin); menu.setLayoutParams(lp); } break; case MotionEvent.ACTION_UP: TranslateAnimation tAnim; if (swipe_tag == SHOW_MENU) { tAnim = new TranslateAnimation(0, max_menu_margin - latestMargin, 0, 0); tAnim.setInterpolator(new DecelerateInterpolator()); tAnim.setDuration(800); menu.startAnimation(tAnim); } else { tAnim = new TranslateAnimation(0, min_menu_margin - latestMargin, 0, 0); tAnim.setDuration(800); menu.startAnimation(tAnim); } //在動畫結束的時刻,移動menu的位置。使menu真正移動。 tAnim.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } @Override public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } @Override public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub if (swipe_tag == SHOW_MENU) { lp.leftMargin = max_menu_margin; menu.setLayoutParams(lp); } else { lp.leftMargin = min_menu_margin; menu.setLayoutParams(lp); } menu.clearAnimation(); } }); break; } return true; } }); } }


如上代碼。監聽menu的onTouch事件,而後依據移動距離移動menu。當手指拿起來時,啓動動畫,使移動繼續進行到結束。

咱們上面提到,View Animation僅僅是繪製出來的效果,發生動畫的組件並非真正移動了,那麼此處爲了解決問題,咱們監聽了AnimationListener。在動畫結束時,將menu的位置移動到動畫結束的位置,這樣就成功移動了menu。效果圖例如如下。由於截圖軟件關係,看起來會卡頓,在真機上測試則全然平滑。



最後附上這篇博客先後的兩份源代碼:


ViewAnimationDemo

SwipeWithAnim

相關文章
相關標籤/搜索