螢幕切換指的是在同一個Activity内螢幕見的切換,最長見的情況就是在一個FrameLayout内有多個頁面,比如一個系統設定頁面;一個個性化設定頁面。
通過檢視OPhone API文檔可以發現,有個android.widget.ViewAnimator類繼承至FrameLayout,ViewAnimator類的作用是為FrameLayout裡面的View切換提供動畫效果。該類有如下幾個和動畫相關的函數: l setInAnimation:設定View進入螢幕時候使用的動畫,該函數有兩個版本,一個接受單個參數,類型為android.view.animation.Animation;一個接受兩個參數,類型為Context和int,分别為Context對象和定義Animation的resourceID。
- setOutAnimation: 設定View退出螢幕時候使用的動畫,參數setInAnimation函數一樣。
- showNext: 調用該函數來顯示FrameLayout裡面的下一個View。
- showPrevious: 調用該函數來顯示FrameLayout裡面的上一個View。
一般不直接使用ViewAnimator而是使用它的兩個子類ViewFlipper和ViewSwitcher。ViewFlipper可以用來指定FrameLayout内多個View之間的切換效果,可以一次指定也可以每次切換的時候都指定單獨的效果。該類額外提供了如下幾個函數:
- isFlipping: 用來判斷View切換是否正在進行
- setFilpInterval:設定View之間切換的時間間隔
- startFlipping:使用上面設定的時間間隔來開始切換所有的View,切換會循環進行
- stopFlipping: 停止View切換
ViewSwitcher 顧名思義Switcher特指在兩個View之間切換。可以通過該類指定一個ViewSwitcher.ViewFactory 工程類來建立這兩個View。該類也具有兩個子類ImageSwitcher、TextSwitcher分别用于圖檔和文本切換。 在教程中通過示例介紹ViewFlipper 的使用,其他的使用方式是類似的。詳細資訊可以參考文檔: http://androidappdocs-staging.appspot.com/reference/android/widget/ViewAnimator.html ViewFlipper示例 記住,ViewFlipper是繼承至FrameLayout的,是以它是一個Layout裡面可以放置多個View。在示例中定義一個ViewFlipper,裡面包含三個ViewGroup作為示例的三個螢幕,每個ViewGroup中包含一個按鈕和一張圖檔,點選按鈕則顯示下一個螢幕。代碼如下(res\layout\main.xml): view plain copy to clipboard print ?
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <ViewFlipper android:id="@+id/details"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:persistentDrawingCache="animation"
- android:flipInterval="1000"
- android:inAnimation="@anim/push_left_in"
- android:outAnimation="@anim/push_left_out"
- >
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <Button
- android:text="Next"
- android:id="@+id/Button_next1"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </Button>
- <ImageView
- android:id="@+id/image1"
- android:src="@drawable/dell1"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </ImageView>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <Button
- android:text="Next"
- android:id="@+id/Button_next2"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </Button>
- <ImageView
- android:id="@+id/image2"
- android:src="@drawable/lg"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </ImageView>
- </LinearLayout>
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <Button
- android:text="Next"
- android:id="@+id/Button_next3"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </Button>
- <ImageView
- android:id="@+id/image3"
- android:src="@drawable/lenovo"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </ImageView>
- </LinearLayout>
- </ViewFlipper>
- </LinearLayout>
很簡單,在Layout定義中指定動畫的相關屬性就可以了,通過persistentDrawingCache指定緩存政策;flipInterval指定每個View動畫之間的時間間隔;inAnimation和outAnimation分别指定View進出使用的動畫效果。動畫效果定義如下: view plain copy to clipboard print ?
- res\anim\push_left_in.xml
- <?xml version="1.0" encoding="utf-8"?>
- <set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate
- android:fromXDelta="100%p"
- android:toXDelta="0"
- android:duration="500"/>
- <alpha
- android:fromAlpha="0.0"
- android:toAlpha="1.0"
- android:duration="500" />
- </set>
- res\anim\push_left_out.xml
- <?xml version="1.0" encoding="utf-8"?>
- <set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate
- android:fromXDelta="0"
- android:toXDelta="-100%p"
- android:duration="500"/>
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="0.0"
- android:duration="500" />
- </set>
Activity代碼如下(src\cc\c\TestActivity.java): view plain copy to clipboard print ?
- public class TestActivity extends Activity {
- private ViewFlipper mViewFlipper;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Button buttonNext1 = (Button) findViewById(R.id.Button_next1);
- mViewFlipper = (ViewFlipper) findViewById(R.id.flipper);
- buttonNext1.setOnClickListener(new View.OnClickListener() {
- public void onClick(View view) {
- //在layout中定義的屬性,也可以在代碼中指定
- // mViewFlipper.setInAnimation(getApplicationContext(), R.anim.push_left_in);
- // mViewFlipper.setOutAnimation(getApplicationContext(), R.anim.push_left_out);
- // mViewFlipper.setPersistentDrawingCache(ViewGroup.PERSISTENT_ALL_CACHES);
- // mViewFlipper.setFlipInterval(1000);
- mViewFlipper.showNext();
- //調用下面的函數将會循環顯示mViewFlipper内的所有View。
- // mViewFlipper.startFlipping();
- }
- });
- Button buttonNext2 = (Button) findViewById(R.id.Button_next2);
- buttonNext2.setOnClickListener(new View.OnClickListener() {
- public void onClick(View view) {
- mViewFlipper.showNext();
- }
- });
- Button buttonNext3 = (Button) findViewById(R.id.Button_next3);
- buttonNext3.setOnClickListener(new View.OnClickListener() {
- public void onClick(View view) {
- mViewFlipper.showNext();
- }
- });
- }
- }
通過手勢移動螢幕 上面是通過螢幕上的按鈕來在螢幕間切換的,這看起來多少有點不符合OPhone的風格,如果要是能通過手勢的左右滑動來實作螢幕的切換就比較優雅了。 通過android.view.GestureDetector類可以檢測各種手勢事件,該類有兩個回調接口分别用來通知具體的事件: GestureDetector.OnDoubleTapListener:用來通知DoubleTap事件,類似于滑鼠的輕按兩下事件,該接口有如下三個回調函數: 1. onDoubleTap(MotionEvent e):通知DoubleTap手勢, 2. onDoubleTapEvent(MotionEvent e):通知DoubleTap手勢中的事件,包含down、up和move事件(這裡指的是在輕按兩下之間發生的事件,例如在同一個地方輕按兩下會産生DoubleTap手勢,而在DoubleTap手勢裡面還會發生down和up事件,這兩個事件由該函數通知); 3. onSingleTapConfirmed(MotionEvent e):用來判定該次點選是SingleTap而不是DoubleTap,如果連續點選兩次就是DoubleTap手勢,如果隻點選一次,OPhone系統等待一段時間後沒有收到第二次點選則判定該次點選為SingleTap而不是DoubleTap,然後觸發SingleTapConfirmed事件。 GestureDetector.OnGestureListener:用來通知普通的手勢事件,該接口有如下六個回調函數: 1. onDown(MotionEvent e):down事件; 2. onSingleTapUp(MotionEvent e):一次點選up事件; 3. onShowPress(MotionEvent e):down事件發生而move或則up還沒發生前觸發該事件; 4. onLongPress(MotionEvent e):長按事件; 5. onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY):滑動手勢事件; 6. onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):在螢幕上拖動事件。 這些事件有些定義的不太容易了解,在示例項目中實作了所有的回調函數,在每個函數中輸出相關的日志,對這些事件不了解的可以運作項目,通過不同的操作來觸發事件,然後觀看logcat輸出日志可有助于對這些事件的了解。 在上述事件中,如果在程式中處理的該事件就傳回true否則傳回false,在GestureDetector中也定義了一個SimpleOnGestureListener類,這是個助手類,實作了上述的所有函數并且都傳回false。如果在項目中隻需要監聽某個事件繼承這個類可以少些幾個空回調函數。 要走上面的程式中添加滑動手勢來實作螢幕切換的話,首先需要定義一個GestureDetector: private GestureDetector mGestureDetector; 并在onCreate函數中初始化: mGestureDetector = new GestureDetector( this); 參數是OnGestureListener,然後讓TestActivity實作 OnGestureListener 和OnDoubleTapListener接口: view plain copy to clipboard print ?
- class TestActivity extends Activity implements OnGestureListener , OnDoubleTapListener
然後在onFling函數中實作切換螢幕的功能: view plain copy to clipboard print ?
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- Log.d(tag, "...onFling...");
- if(e1.getX() > e2.getX()) {//move to left
- mViewFlipper.showNext();
- }else if(e1.getX() < e2.getX()) {
- mViewFlipper.setInAnimation(getApplicationContext(), R.anim.push_right_in);
- mViewFlipper.setOutAnimation(getApplicationContext(), R.anim.push_right_out);
- mViewFlipper.showPrevious();
- mViewFlipper.setInAnimation(getApplicationContext(), R.anim.push_left_in);
- mViewFlipper.setOutAnimation(getApplicationContext(), R.anim.push_left_out);
- }else {
- return false;
- }
- return true;
- }
這裡實作的功能是從右往左滑動則切換到上一個View,從左往右滑動則切換到下一個View,并且使用不同的in、out 動畫使切換效果看起來統一一些。 然後在onDoubleTap中實作輕按兩下自動切換的效果,再次輕按兩下則停止: view plain copy to clipboard print ?
- public boolean onDoubleTap(MotionEvent e) {
- Log.d(tag, "...onDoubleTap...");
- if(mViewFlipper.isFlipping()) {
- mViewFlipper.stopFlipping();
- }else {
- mViewFlipper.startFlipping();
- }
- return true;
- }
到這裡手勢代碼就完成了,現在可以通過左右滑動切換View并且輕按兩下可以自動切換View。細心的讀者這裡可能會發現一個問題,上面在建立mGestureDetector 的時候使用的是如下代碼: mGestureDetector = new GestureDetector( this); 這裡的參數為OnGestureListener,而且GestureDetector有個函數setOnDoubleTapListener來設定OnDoubleTapListener,在上面的代碼中并沒有設定OnDoubleTapListener,那麼onDoubleTap事件是如何調用的呢?這裡的玄機就要去探探 GestureDetector(OnGestureListener l)這個構造函數的源代碼了: view plain copy to clipboard print ?
- public GestureDetector(OnGestureListener listener) {
- this(null, listener, null);
- }
調用了另外一個構造函數: view plain copy to clipboard print ?
- public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
- if (handler != null) {
- mHandler = new GestureHandler(handler);
- } else {
- mHandler = new GestureHandler();
- }
- mListener = listener;
- if (listener instanceof OnDoubleTapListener) {
- setOnDoubleTapListener((OnDoubleTapListener) listener);
- }
- init(context);
注意到listener instanceof OnDoubleTapListener沒有?現在明白了吧。