Android動畫之二:View Animation

來源:互聯網
上載者:User

標籤:animation   android   動畫   

如上一篇部落格《Android動畫之一:Drawable Animation》所說,android動畫主要分為三大部分,上一篇部落格已經講解Drawable Animation的用法,即逐幀地顯示圖片,經常運用於動態顯示一個進度動畫,這是出現頻率最高的應用情境。接下來,我們這篇文章將循序漸進,介紹View Animation。

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

View Animation的效果由四個因素決定:1)初始狀態;2)結束狀態;3)期間;4)Interpolator。所以要定義一個View Animation,你只要定義以上四個因素,中間的過程怎麼變化則有系統自動計算出來。其中前3個因素很容易理解,第四個因素Interpolator比較特別,這個單詞不知道怎麼翻譯比較適合,很多書籍的翻譯都很奇怪。Interpolator是決定動畫進行過程的速度變化。比如:你將一個按鈕從螢幕左側運動到螢幕右側。可以讓它一直加速前進,或者先減速然後減速,這就是Interpolator發揮的作用,具體使用方法下面會說,先從簡單的說起。

像Drawable Animation一樣,定義一個View Animation可以用代碼的方式,也可以用XML檔案的方式。我們先來寫一個最簡單的例子,對一個helloworld字串進行移動,微調,向內,變暗,分別用代碼實現和XML檔案實現。先用代碼實現。

首先建立工程:ViewAnimationDemo,並建立一個布局檔案:animationjavacode.xml,如下:

ViewAnimationDemo\res\layout\animationjavacode.xml

<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

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() {@Overridepublic 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: 確定InterpolatortAnim.setInterpolator(new AccelerateDecelerateInterpolator());// 啟動動畫translation.startAnimation(tAnim);rotate.startAnimation(rAnima);scale.startAnimation(sAnima);alpha.startAnimation(aAnima);}});            }}

從代碼中不難看到,首先確定了動畫的起始狀態和結束狀態,然後通過setDuration(2000)設定期間,如果這裡不設定期間,將預設為30mx,基本肉眼看不到。最後我們設定了一個Interpolator,此處設定效果是動畫先減速進行,然後減速。預設狀態時勻速進行。沒錯,Interpolator的基本用法就是這麼容易。以上代碼如下:


接下來講解怎麼用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共用給子節點。其它子標籤的屬性很容易理解,基本看屬性名稱字就能懂,除了其中兩個,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

接下來我們定義一個布局檔案,該布局檔案只有一張圖片,一個按鈕,通過點擊按鈕觸發圖片進行動畫,該布局檔案比較簡單,這裡不列出。如何在該布局檔案對應的activity代碼中啟動動畫呢,代碼如下:

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

public class AnimaXmlActivity extends Activity {private Button btn;private ImageView img;@Overrideprotected 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() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubAnimation anim = AnimationUtils.loadAnimation(AnimaXmlActivity.this, R.anim.myanim);img.startAnimation(anim);}});}}

以上代碼很容易理解,我們一般使用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) */@Overrideprotected 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() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubint 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() {@Overridepublic void onAnimationStart(Animation animation) {// TODO Auto-generated method stub}@Overridepublic void onAnimationRepeat(Animation animation) {// TODO Auto-generated method stub}@Overridepublic void onAnimationEnd(Animation animation) {// TODO Auto-generated method stubif (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




Android動畫之二:View Animation

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.