1.基本動畫使用方式
在包com.example.android.apis.view下面的Animation1~3有各種使用方式,分別來進行介紹。
Animation1.java
如下所示(原始代碼在包com.example.android.apis.view下面)
package
com.example.android.apis.view;
// Need the following import to
get access to the app resources, since this
// class is in a sub-package.
import
com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import
android.view.animation.Animation;
import
android.view.animation.AnimationUtils;
public class Animation1 extends
Activity implements View.OnClickListener {
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_1);
View loginButton =
findViewById(R.id.login);
loginButton.setOnClickListener(this);
}
public void onClick(View v) {
Animation shake =
AnimationUtils.loadAnimation(this, R.anim.shake);
findViewById(R.id.pw).startAnimation(shake);
}
R.layout.animation_1對應的XML文件為:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:text="@string/animation_1_instructions"
/>
<EditText
android:id="@+id/pw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:singleLine="true"
android:password="true"
/>
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/googlelogin_login"
/>
</LinearLayout>
此XML文件為程序的主運行界面。如何實現動畫呢?
實際上實現動畫有兩種方式,一種是在代碼中構造Animation對象,一種是在XML文件中定義相關的資源。
如果構造對象,則應該分別新建AlphaAnimation等對象,而如果是XML文件中,則應該使用alpha等標簽。在本例中,使用的是XML文件來創建Animation對象。
XML
中
alpha
漸變透明度動畫效果
scale
漸變尺寸伸縮動畫效果
translate
畫面轉換位置移動動畫效果
rotate
畫面轉移旋轉動畫效果
|
JavaCode
中
AlphaAnimation
漸變透明度動畫效果
ScaleAnimation
漸變尺寸伸縮動畫效果
TranslateAnimation
畫面轉換位置移動動畫效果
RotateAnimation
畫面轉移旋轉動畫效果
|
在OnCreate函數中,通過綁定Button實現對按鈕事件的監聽。
在onClick函數中,定義了點擊按鈕時候觸發的動作,這里面的代碼即實現相應的特效的代碼。從代碼中可以看到,這里首先執行下面的代碼:
Animation shake =
AnimationUtils.loadAnimation(this, R.anim.shake);
findViewById(R.id.pw).startAnimation(shake);
在這段代碼中,通過loadAnimation函數來載入動畫元素,而動畫資源則是在R.anim.shake中定義。找到該XML文件,內容如下:
<?xml version="1.0"
encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="10"
android:duration="1000"
android:interpolator="@anim/cycle_7"
/>
從中可以看到,該XML文件中,通過標簽tranlate來定義平移的動作,并且設定了相關的參數,另外,注意其中的interpolator參數,該參數的設定是通過另外一個XML文件cycle_7來設定的。內容如下:
<?xml version="1.0"
encoding="utf-8"?>
<cycleInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
android:cycles="7" />
至此,完成了動畫的Animation,即參數的設定,最終就是調用AnimationUtils.loadAnimation來創建Animation對象shake,然后通過某個View的字函數startAnimation在該View上啟動該動畫。
比如這里:
findViewById(R.id.pw).startAnimation(shake);
首先獲得的是password的那個EditText的View,然后在該View上調用startAnimation方法,啟動shake這種動畫。效果就是點擊login登錄按鈕后,password的編輯框會出現來回抖動的效果。
既然弄清楚了Animation的兩種使用方法,并且在上面中通過剖析Android的API
Demo了解了使用XML來實現動畫效果的例子,那么下面我們自己動手,利用Java
Code的辦法,實現同樣的效果。
具體過程如下:
-
首先新建一個Android項目功能,然后編輯main.xml文件,添加一個Button和EditText控件,實現類似的原來那個例子那樣的控件效果。
-
編輯OnCreate函數,在代碼中實現前面的這些效果。
代碼如下:
import android.app.Activity;
import
android.app.SearchManager.OnCancelListener;
import android.os.Bundle;
import android.view.View;
import
android.view.View.OnClickListener;
import
android.view.animation.Animation;
import
android.view.animation.AnimationUtils;
import
android.view.animation.CycleInterpolator;
import
android.view.animation.Interpolator;
import
android.view.animation.TranslateAnimation;
public class AnimationTest
extends Activity {
/** Called when the activity
is first created. */
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View login =
findViewById(R.id.login);
login.setOnClickListener(new
OnClickListener() {
@Override
public void
onClick(View v) {
TranslateAnimation
ta = new TranslateAnimation(0, 10, 0, 0);
ta.setDuration(1000);
ta.setInterpolator(new
CycleInterpolator(7));
findViewById(R.id.passwd).startAnimation(ta);
}
});
}
}
-
運行該工程后,就能夠達到和Demo例子中同樣的效果。
-
代碼解讀:
其實功能很簡單,原始Demo是通過loadAnimation函數讀取XML文件,那么我們只需要新建對應的Animation對象就行了。原始例子中使用的是Translate標簽,對應的就是TranslateAnimation類,為此新建該對象,設定的參數就是原XML文件中的fromXDelta,toXDelta等等,由于原來的標簽沒有設定Y方向上的參數,所以使用默認的0,0.然后觀察發現原始還是用了一個cycleInterpolator的XML資源,其中定義了一個cycle值,為此同樣找到Java
Code對應的類,new一個這樣的對象并設定參數。最終同樣的對密碼控件實現該特效效果,達到同樣的效果。
2.利用XML來定義動畫
在分析完上面這個最基本的動畫特效使用之后,下面繼續分析API
Demo中剩余的兩個例子,它們分別是位于com.example.android.apis.view包下面的Animation2.java和Animation3.java文件。
首先分析Animation2.java對應的工程,原文件如下。
package
com.example.android.apis.view;
// Need the following import to
get access to the app resources, since this
// class is in a sub-package.
import
com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import
android.view.animation.AnimationUtils;
import
android.widget.AdapterView;
import
android.widget.ArrayAdapter;
import android.widget.Spinner;
import
android.widget.ViewFlipper;
public class Animation2 extends
Activity implements
AdapterView.OnItemSelectedListener
{
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_2);
mFlipper = ((ViewFlipper)
this.findViewById(R.id.flipper));
mFlipper.startFlipping();
Spinner s = (Spinner)
findViewById(R.id.spinner);
ArrayAdapter<String>
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
mStrings);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
s.setOnItemSelectedListener(this);
}
public void
onItemSelected(AdapterView parent, View v, int position, long id) {
switch (position) {
case 0:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_out));
break;
case 1:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_out));
break;
case 2:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.fade_out));
break;
default:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.hyperspace_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.hyperspace_out));
break;
}
}
public void
onNothingSelected(AdapterView parent) {
}
private String[] mStrings = {
"Push up",
"Push left", "Cross fade", "Hyperspace"};
private ViewFlipper mFlipper;
}
從代碼中可以看到,該類有一個ViewFlipper類型的成員變量,以及定義了菜單項的字符串數組。在OnCreate函數中,首先設定程序的主界面布局為animation_2.xml文件,該文件的內容如下:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:flipInterval="2000"
android:layout_marginBottom="20dip"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_3"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_4"/>
</ViewFlipper>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:text="@string/animation_2_instructions"
/>
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
從該XML文件中可以看到主界面的組成,一個ViewFlipper控件,一個顯示提示信息的TextView,以及一個Spinner控件。所謂的ViewFlipper是一個多View的集合,但是每次都只能夠顯示出一個View,從最終的動畫效果可以看到,該ViewFlipper中的每一個TextView,都以事先定義的某種動畫形式不斷的切換,輪流的顯示出來。Spinner則是一個選擇菜單,點擊后出現下拉菜單,讓用戶選擇某個選項,在這里,每一個選項的內容就是數組mStrings的內容。
圖
2-1
Spinner
的效果
最終的效果就是,用戶通過點擊Spinner中的某個選項,可以選擇不同的效果。而上方的那個ViewFlipper則以該種動畫效果輪流顯示出每一個TextView,ViewFlipper的四個子TextView得以輪流動畫顯示,消失。
在OnCreate函數中,首先獲得ViewFlipper控件,然后通過調用startFlipping函數,開啟一個計時器來循環顯示出子View。此后,獲得Spinner控件,然后利用mString數組創建一個ArrayAdapter,并指定為該Spinner的Adapter,最后,調用setOnItemSelectedListener開啟一個監聽選項的監聽器,每當選擇不同的選項時,進入不同的處理過程。
在分析完OnCreate函數后,整個工程就剩下選項被選中時候的函數實現了,即onItemSelected函數,當程序啟動后OnCreate函數中添加了監視器,開始監聽。用戶一點點擊選擇了某個選項,就會根據這個position來進入不同的處理過程中。從代碼中可以看到,switch……case的結構,分別針對用戶選擇
"Push
up", "Push left", "Cross fade", "Hyperspace"
這四個菜單時候的動作,在每個選項中的動作類似,因此只針對第一個進行介紹。
case 0:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_out));
break;
在用戶選擇了第一個Push
Up菜單后,該ViewFlipper通過使用setInAnimation函數來設定一個進入到屏幕中的View的動畫(Specifies
the animation used to animate a View that enters the
screen.)通過使用setOutAnimation來指定一個離開屏幕時候的View的動畫(Specifies
the animation used to
animate a View that exit the
screen.)這兩個函數的參數都是一個Animation類型的對象,在前面第一部分的講解中知道,有兩種辦法可以得到該對象。
-
XML
文件中定義,利用AnimationUtils.loadAnimation來載入該動畫
-
利用Java
Code的Animation類來創建各種類型的對象。
在這里,使用的是第一種辦法。查看相應的XML文件。
push_up_in.xml
文件
<?xml version="1.0"
encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%p" android:toYDelta="0"
android:duration="300"/>
<alpha
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="300" />
</set>
從代碼中可以看到,這是一個動畫集合,包括一個translate,即平移動畫,以及一個alpha,即透明度漸變的動畫。在標簽中分別設定了變化的參數,持續的時間等等。
從代碼以及最終的運行效果可以知道,該動畫特效就是,進入的時候從Y軸坐標100變化到0,即從下往上進入屏幕,透明度從0變為1,即從開始的不可見,逐漸變的清晰可見。類似的,push_up_out則實現相反的效果,在XML文件中有相應的表示。
同理,push_up_out.xml文件也可以采用類似的方法分析。
至此,我們分析完了第二個工程,對整個動畫如何實現,如何正確的調用Animation函數都有了一個更清晰的認識。
3.利用JavaCode來實現動畫
最后,我們簡單來分析下第三個工程,因為上面兩個工程的分析,最后一個的實現機制也是類似的。
Animation3.java
package
com.example.android.apis.view;
// Need the following import to
get access to the app resources, since this
// class is in a sub-package.
import
com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import
android.view.animation.AnimationUtils;
import
android.view.animation.Animation;
import
android.view.animation.TranslateAnimation;
import
android.widget.AdapterView;
import
android.widget.ArrayAdapter;
import android.widget.Spinner;
public class Animation3 extends
Activity implements AdapterView.OnItemSelectedListener {
private static final String[]
INTERPOLATORS = {
"Accelerate",
"Decelerate", "Accelerate/Decelerate",
"Anticipate",
"Overshoot", "Anticipate/Overshoot",
"Bounce"
};
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_3);
Spinner s = (Spinner)
findViewById(R.id.spinner);
ArrayAdapter<String>
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
INTERPOLATORS);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
s.setOnItemSelectedListener(this);
}
public void
onItemSelected(AdapterView parent, View v, int position, long id) {
final View target =
findViewById(R.id.target);
final View targetParent =
(View) target.getParent();
Animation a = new
TranslateAnimation(0.0f,
targetParent.getWidth()
- target.getWidth() - targetParent.getPaddingLeft() -
targetParent.getPaddingRight(),
0.0f, 0.0f);
a.setDuration(1000);
a.setStartOffset(300);
a.setRepeatMode(Animation.RESTART);
a.setRepeatCount(Animation.INFINITE);
switch (position) {
case 0:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_interpolator));
break;
case 1:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.decelerate_interpolator));
break;
case 2:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_decelerate_interpolator));
break;
case 3:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.anticipate_interpolator));
break;
case 4:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.overshoot_interpolator));
break;
case 5:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.anticipate_overshoot_interpolator));
break;
case 6:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.bounce_interpolator));
break;
}
target.startAnimation(a);
}
public void
onNothingSelected(AdapterView parent) {
}
}
同工程2,在OnCreate函數中,設定了程序運行的主界面的layout,包括兩個TextView和一個Spinner,Spinner同樣是一個選擇菜單,兩個TextView中,一個是顯示的標簽,保持不變,另外一個實現動畫特效的View。
Animation3.xml文件:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false">
<TextView
android:id="@+id/target"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="26sp"
android:text="@string/animation_3_text"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginBottom="5dip"
android:text="@string/animation_2_instructions"
/>
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
圖3-1 Spinner選項
回到代碼中,當用戶選擇某個選項時,進入到onItemSelected函數,此時獲得帶顯示動畫特效的那個TextView的引用以及它的父View,然后新建一個Animatioin,注意此處沒有通過XML文件來定義,而是利用Java
Code來創建動畫特效。通過設置各種參數,定義特效的實現形式。其中下面的代碼需要注意:
Animation a = new
TranslateAnimation(0.0f,
targetParent.getWidth()-target.getWidth()-targetParent.getPaddingLeft()
-
targetParent.getPaddingRight(),0.0f,
0.0f);</LinearLayout>
為何要使用targetParent來計算長寬,而不是直接使用自己這個TextView呢?原因在于,該TextView是位于整個layout中的,而待實現的這個特效,實際上是要這個TextView在父layout上面左右移動(或者是其他運行形式),所以,運動的范圍要局限在父對象中,因此是使用targetParent而不是target來設定該Animation。
余下的工作就是設定各種參數,對于本函數中的Swtich……case,則只是起到了修改Interpolator的作用,用戶在選中不同的Interpolator后,該TextView將采用不同的形式來運動,那么,何為Interpolator對象呢?
SDK中的解釋再清楚不過了:
"
An
interpolator defines the rate of change of an animation. This allows
the basic animation effects (alpha, scale, translate, rotate) to be
accelerated, decelerated, repeated, etc."
也就是說Interpolator是一個定義了動畫變化的快慢速率的東西,它允許定義基本的動畫效果為加速,減速或者重復顯示等等效果。
最后,完成了上面的工作后,通過調用target.startAnimation(a);來使得target這個TextView按照設定的動畫效果a進行變換顯示。
最后做一個總結:實現動畫的方式有兩種:XML和JavaCode,還有,學習使用的最好辦法是看Sample,查SDK文檔,雖然初看Sample可能覺得有些困難,但是慢慢查文檔,遇到復雜的用法和控件就先查查文檔看看有沒有,或者Google之,慢慢就會明白了。還有,學習之余多進行變化,比如換種方式實現,或者注釋掉某行代碼,再查看效果,即可對關鍵點有一個更清晰的了解。
posted on 2011-10-22 10:27
deercoder 閱讀(4840)
評論(0) 編輯 收藏 引用 所屬分類:
Android