Android系統內建一個Gallery瀏覽圖片的應用,通過手指拖動時能夠非常流暢的顯示圖片,使用者互動和體驗都很好。
本樣本就是通過Gallery和自訂的View,模仿實現一個仿Gallery映像集的圖片瀏覽效果。如下:
1、基本原理
在 Activity 中實現 OnGestureListener 的介面 onFling() 手勢事件,通過自訂的 View 繪製draw() 圖片
2、Activity
Activity中,通過onTouchEvent() 註冊 myGesture.onTouchEvent(event)
@Override<br />public boolean onTouchEvent(MotionEvent event) {<br />switch (event.getAction()) {<br />case MotionEvent.ACTION_UP:<br />flingView.onFling(0);// 手指抬起後,重設滑動距離offsetX = 0<br />break;<br />}</p><p>return myGesture.onTouchEvent(event);<br />}
接著實現介面OnGestureListener 的 onScroll()方法,給繼承自View的 FlingView 的handleScroll()成員方法傳遞滑動參數,擷取滑動的x軸距離
@Override<br />public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {<br />flingView.handleScroll(-1 * (int) distanceX);<br />return true;<br />}
接著實現介面OnGestureListener 的 OnFling()方法,給繼承自View的 FlingView 的onFling()成員方法傳遞滑動參數,擷取手勢的速度
@Override<br />public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {<br />flingView.onFling((int) - velocityX);<br />return true;<br />}
3、FlingView
FlingView中,擷取來自Activity中的手勢速度
public void onFling(int paramFloat1) {<br />if (offsetX > GalleryDemoActivity.deviceScreenWidth / 5) {<br />if (fBitmap != null) {<br />isFling = true;<br />isFlingRight = true;<br />}<br />} else if (offsetX < -GalleryDemoActivity.deviceScreenWidth / 5) {<br />if (nBitmap != null) {<br />isFling = true;<br />isFlingLeft = true;<br />}<br />}<br />// 開始動畫效果<br />startAnimation(new MyAnimation());<br />}
在滑動過程中,通過實現View的Draw()方法繪製圖片,注意:此時需要同時繪製當前圖片(擷取焦點)和下一張圖片(即將擷取焦點)共兩張圖片
@Override<br />public void draw(Canvas canvas) {<br />Paint paint = new Paint();<br />Rect rect = new Rect();<br />canvas.drawColor(Color.BLACK);</p><p>// 繪製當前圖片<br />if (bitmap != null) {<br />int left = offsetX;<br />int top = offsetY;<br />int right = offsetX + GalleryDemoActivity.deviceScreenWidth;<br />int bottom = offsetY + GalleryDemoActivity.deviceScreenHeight;<br />rect.set(left, top, right, bottom);<br />canvas.drawBitmap(bitmap, null, rect, paint);<br />}</p><p>// 繪製下一張圖片<br />if (offsetX < 0) {// 向左滑動<br />if (nBitmap != null) {<br />int left = GalleryDemoActivity.deviceScreenWidth + 15 + offsetX;<br />int top = 0;<br />int right = left + GalleryDemoActivity.deviceScreenWidth;<br />int bottom = GalleryDemoActivity.deviceScreenHeight;<br />rect.set(left, top, right, bottom);<br />canvas.drawBitmap(nBitmap, null, rect, paint);<br />}<br />} else if (offsetX > 0) {// 向右滑動<br />if (fBitmap != null) {<br />int left = -GalleryDemoActivity.deviceScreenWidth - 15 + offsetX;<br />int top = 0;<br />int right = left + GalleryDemoActivity.deviceScreenWidth;<br />int bottom = GalleryDemoActivity.deviceScreenHeight;<br />rect.set(left, top, right, bottom);<br />canvas.drawBitmap(fBitmap, null, rect, paint);<br />}<br />}<br />}在滑動圖片結束後,需要做滑動動畫後的處理,重新設定當前圖片和當前圖片的上一張和下一張的狀態,為下次滑動做準備
@Override<br />protected void onAnimationEnd() {<br />if (isFlingRight) {// 向右滑動,position減1<br />nBitmap = bitmap;<br />bitmap = fBitmap;<br />fBitmap = null;<br />postion = postion - 1;<br />} else if (isFlingLeft) {// 向左滑動,position加1<br />fBitmap = bitmap;<br />bitmap = nBitmap;<br />nBitmap = null;<br />postion = postion + 1;<br />}</p><p>isFlingRight = false;<br />isFlingLeft = false;<br />isFling = false;<br />offsetX = 0;<br />if (fBitmap == null && offsetX == 0) {// 如果前一張圖片為空白(向右滑),則重設前一張圖片(position - 1)<br />if (postion > 0) {<br />fBitmap = getBitmap(postion - 1);<br />}</p><p>} else if (nBitmap == null && offsetX == 0) {// 如果後一張圖片為空白(向左滑),則重設後一張圖片(position + 1)<br />if (postion < bitmaps.length - 1) {<br />nBitmap = getBitmap(postion + 1);<br />}<br />}<br />clearAnimation();<br />}
4、手勢座標介紹
本樣本中,用到了OnGestureListener介面的onScroll()和OnFling()方法,涉及到了Android系統座標及觸摸MotionEvent e1和e2、速度velocityX、velocityY等值
Android螢幕座標系如(左)
(1)MotionEvent中 e1是手指第一次按上螢幕的起點,e2是抬起手指離開螢幕的終點,根據Android螢幕座標系可知:
手指向右滑動,終點(e2)在起點(e1)的右側,有e2.getX() - e1.getX() 大於0
手指向左滑動,終點(e2)在起點(e1)的左側,有e2.getX() - e1.getX() 小於0
手指向下滑動,終點(e2)在起點(e1)的下側,有e2.getY() - e1.getY() 大於0
手指向上滑動,終點(e2)在起點(e1)的上側,有e2.getY() - e1.getY() 小於0
(2)onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
distanceX,是前後兩次call的X距離,不是e2與e1的水平距離
distanceX,是前後兩次call的Y距離,不是e2與e1的垂直距離
具體數值的方向,請詳見(中)
(3)onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
velocityX,是X軸的每秒速度
velocityY,是Y軸的每秒速度
具體數值的方向,請詳見(右)
仔細觀察可以發現:velocityX、velocityY的方向與distanceX、distanceY方向正好相反
更多OnGestureListener介面函數介紹,請見上一篇部落格 Android 滑動效果入門篇(一)—— ViewFlipper
樣本源碼下載