ViewFlipper的使用(手勢滑屏)
屏幕切換指的是在同一個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 的使用,其他的使用方式是類似的。詳細信息可以參考文檔:
ViewFlipper示例
記住,ViewFlipper是繼承至FrameLayout的,所以它是一個Layout里面可以放置多個View。在示例中定義一個ViewFlipper,里面包含三個ViewGroup作為示例的三個屏幕,每個ViewGroup中包含一個按鈕和一張圖片,點擊按鈕則顯示下一個屏幕。代碼如下(res\layout\main.xml):
view plaincopy to clipboardprint? <?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進出使用的動畫效果。動畫效果定義如下:
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):
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接口:
- class TestActivity extends Activity implements OnGestureListener , OnDoubleTapListener
然后在onFling函數中實現切換屏幕的功能:
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中實現雙擊自動切換的效果,再次雙擊則停止:
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)這個構造函數的源代碼了:
public GestureDetector(OnGestureListener listener) { this(null, listener, null); }
調用了另外一個構造函數:
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沒有?現在明白了吧。
來自網易
轉載 http://blog.csdn.net/chenglibin1988/article/details/6662112