手勢其實是一個比較復雜的東西,首先是因為處理的時機。Android中觸摸屏的事件其實只有ACTION_DOWN、ACTION_MOVE和ACTION_UP這三種,當然我們實現手勢的邏輯時,一般會用到GestureDetector,它有許多封裝好的事件回調接口,比如onFling、onLongPress、onScroll等,其實這些事件只是對上面那三個基本時間的包裝而已:即三個基本事件按一定的序列出現,則會觸發響應的GestureDetector中的事件,比如ACTION_DOWN 加上三個ACTION_MOVE再加上ACTION_UP就是一次Fling事件等等。
雖然手勢能給用戶帶來比較新奇好玩的體驗,GestureDetector這樣的接口很容易理解,但是卻也有很多問題,主要是自定義手勢時。假如我們要實現一個自定義的手勢,即當用戶在觸摸屏上畫圓時響應我們的事件處理邏輯,那么當用戶畫圓時,其實也是一個Scroll事件,這時候就不太好確定到底響應畫圓事件還是Scroll事件了。
手勢帶來的另一個問題是UI的體驗,大多數情況下我們需要考慮到用戶手指移動的加速度、反饋、期望等,比如快速的滑動和低速的滑動給用戶的心理預期是完全不同的,這方面做得比較完美的要數MacBook上的TouchPad了,從單指移動鼠標、雙指窗口內移動,到三指窗口間切換、四指返回Home,給用戶的體驗算是十分優秀的了。當然這都是交互的內容了,不再過多討論,一般產品中也不建議做太復雜的手勢。
一般情況下我們用的比較多的手勢就是單指拖拽、雙指縮放圖片這樣的簡單手勢,下面的代碼是ImageView實現單指和雙指這兩種手勢的代碼,沒有用到GestureDetector,而是僅僅對onTouch事件進行處理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
float mCurrentScale = 1; float last_x = -1; float last_y = -1; mImage.setOnTouchListener(new OnTouchListener() { float baseValue; @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub // return ArtFilterActivity.this.mGestureDetector.onTouchEvent(event); if (event.getAction() == MotionEvent.ACTION_DOWN) { baseValue = 0; float x = last_x = event.getRawX(); float y = last_y = event.getRawY(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (event.getPointerCount() == 2) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); float value = (float) Math.sqrt(x * x + y * y);// 計算兩點的距離 if (baseValue == 0) { baseValue = value; } else { if (value - baseValue >= 10 || value - baseValue <= -10) { float scale = value / baseValue;// 當前兩點間的距離除以手指落下時兩點間的距離就是需要縮放的比例。 img_scale(scale); //縮放圖片 } } } else if (event.getPointerCount() == 1) { float x = event.getRawX(); float y = event.getRawY(); x -= last_x; y -= last_y; if (x >= 10 || y >= 10 || x <= -10 || y <= -10) img_transport(x, y); //移動圖片位置 last_x = event.getRawX(); last_y = event.getRawY(); } } else if (event.getAction() == MotionEvent.ACTION_UP) { } return true; } }); |
關於完整的代碼,其實在之前關於圖像處理的文章中提供下載的代碼中就已經實現了,或者直接點擊這里下載:代碼