Android 手勢處理
作為忠實的 Android 系統(tǒng)用戶,你應(yīng)該會經(jīng)常用到各種手勢:點擊、長按、雙擊、縮放、滑動、拖拽、返回等等,可以說豐富的手勢可以讓用戶更加簡潔方便的使用 App,甚至直接影響到 App 的使用體驗。這些手勢都是系統(tǒng)為我們提供的操作方式,今天來一起看看如何捕捉用戶的手勢輸入。
1 手勢檢測工具
在前面的章節(jié)我們講到過觸摸事件:onTouch(),它是一切手勢的開始,所以根據(jù)onTouch
的幾種事件類型我們可以判斷出用戶的各種手勢,但是對于一些相對復(fù)雜的手勢(比如縮放、旋轉(zhuǎn)、雙擊等)判斷起來會比較麻煩。不過這些都不用擔(dān)心Android 系統(tǒng)為我們提供了一個叫GestureDetector
的工具類,通過它我們可以輕松的接收到用戶的各種復(fù)雜手勢。
GestureDetector
的使用方法非常簡單,首先創(chuàng)建一個類繼承自GestureDetector.SimpleOnGestureListener
,然后覆寫其中需要監(jiān)聽的事件方法,如下:
GestureDetector mGesture;
mGesture = new GestureDetector(this, new Gesture());
class Gesture extends GestureDetector.SimpleOnGestureListener{
public boolean onSingleTapUp(MotionEvent ev) {
// 處理單擊事件
}
public void onLongPress(MotionEvent ev) {
// 處理長按
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// 處理滑動手勢
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// 處理快速滾動
}
}
2 GestureListener 相關(guān)事件
Gesture 支持很多復(fù)雜的手勢處理,基本上處理手勢用它就沒錯了。這里挑幾個最常見的進(jìn)行詳細(xì)的講解,其余的也大同小異。
- onDown: 觸摸事件,同
onTouch
事件當(dāng)中的ACTION_DOWN
,所有手勢的起點 - onSingleTapUp: 單擊
- onLongPress: 長按
- onScroll: 滾動
- onFling: 手指快速滾動,并離開屏幕,在屏幕繼續(xù)滾動的時候觸發(fā)
3 手勢的處理方式
在寫好了第 1 小節(jié)的代碼之后,關(guān)鍵就是去實現(xiàn)事件處理代碼了,點擊、長按等事件都比較好理解,這里以縮放手勢為例講解一下具體的手勢處理邏輯。
3.1 縮放處理工具類
縮放的手勢處理是通過ScaleGestureDetector
來實現(xiàn)的,首先創(chuàng)建一個ScaleGestureDetector
:
ScaleGestureDetector scaleGestureDetector;
scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
構(gòu)造器需要傳入兩個參數(shù),一個是上下文 context,一個是縮放時間監(jiān)聽器。所以,在此之前我們還需要創(chuàng)建一個ScaleListener
,然后覆寫OnTouchEvent(MotionEvent e)
,并且在OnTouchEvent
中將觸摸事件傳遞給 ScaleGestureDetector,代碼如下:
public boolean onTouchEvent(MotionEvent ev) {
SGD.onTouchEvent(ev);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
return true;
}
}
3.2 手勢處理中常用的系統(tǒng)方法
在處理手勢的過程中,我們還會調(diào)用一些系統(tǒng)方法來輔助完成事件處理,主要有以下幾個:
- getEventTime():
獲取事件發(fā)生的時間戳 - getFocusX():
獲取當(dāng)前手勢焦點的 X 軸坐標(biāo) - getFocusY():
獲取當(dāng)前手勢焦點的 Y 軸坐標(biāo) - getTimeDelta():
獲取兩次縮放時間的時間差 - isInProgress():
判斷當(dāng)前是否正處理縮放過程中 - onTouchEvent(MotionEvent event):
接收系統(tǒng)觸摸事件,并分發(fā)到相應(yīng)的監(jiān)聽器中
4 手勢處理示例
本節(jié)通過GestureDetector
完成一個類似微信聊天中的大圖縮放功能,即通過雙指往外或者向內(nèi)的手勢來控制圖片的放大、縮小。
4.1 編寫布局文件
布局文件非常簡單,核心就是一個 ImageView,用來承載我們縮放的目標(biāo)圖片。需要注意的是,這里要將圖片的 scaleType
設(shè)置成“matrix”,用于后續(xù)做縮放:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="手勢處理示例"
android:textSize="35sp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textview"
android:layout_centerHorizontal="true"
android:text="慕課 Android 教程"
android:textColor="#ff7aff24"
android:textSize="35dp" />
<ImageView
android:id="@+id/imageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_below="@+id/textView"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:scaleType="matrix"
android:src="@drawable/avatar" />
</RelativeLayout>
4.2 手勢處理邏輯編寫
手勢處理基本遵循上述邏輯,分為 4 步:
- 第一步: 首先創(chuàng)建一個
ScaleListener
,覆寫onScale
方法來接收縮放手勢; - 第二步: 然后創(chuàng)建
ScaleGestureDetector
,構(gòu)造器傳入 context 對象及剛剛創(chuàng)建的ScaleListener
對象; - 第三步: 接著覆寫
onTouchEvent(MotionEvent ev)
,調(diào)用 ScaleGestureDetector 的onTouchEvent()
方法,傳入 MotionEvent,這樣就把觸摸事件傳遞給了ScaleGestureDetector
,后續(xù)的整個縮放手勢就全權(quán)交給ScaleGestureDetector
來處理。 - 第四步: 最后我們只需要在
onScale()
中完成我們的圖片縮放邏輯即可。
代碼如下,整體思路還是比較清晰的:
package com.emercy.myapplication;
import android.app.Activity;
import android.graphics.Matrix;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView iv;
private Matrix matrix = new Matrix();
private float scale = 1f;
private ScaleGestureDetector mDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.imageView);
// 第2步:創(chuàng)建縮放手勢檢測器ScaleGestureDetector,用于檢測縮放手勢
mDetector = new ScaleGestureDetector(this, new ScaleListener());
}
// 第3步:覆寫onTouchEvent,將觸摸事件傳遞給ScaleGestureDetector
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}
// 第1步:創(chuàng)建縮放監(jiān)聽器,用于接收縮放事件
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
// 第4步:實現(xiàn)圖片縮放邏輯
scale *= detector.getScaleFactor();
scale = Math.max(0.1f, Math.min(scale, 5.0f));
matrix.setScale(scale, scale);
iv.setImageMatrix(matrix);
return true;
}
}
}
編譯運(yùn)行效果如下:
我們用雙指向外或者向內(nèi)滑動,就可以看到“照騙”會跟隨我們的手勢而放大/縮小,整個流程非常順滑無污染,歡迎自行編譯體驗。
溫馨提示: 照騙高清,請謹(jǐn)慎放大
5 小結(jié)
本節(jié)介紹了一個非常強(qiáng)大的手勢處理工具——GestureDetector,如果不使用它,我們需要自行監(jiān)聽onTouch
事件,然后結(jié)合“DOWN”、“MOVE”、“UP”等等各種不同的 onTouch 事件組合起來才能檢測出一些復(fù)雜的手勢,這一切 GestureDetector 都幫助我們實現(xiàn)了。學(xué)完這一章,我們只需要按照幾個簡單的步驟就可以進(jìn)行復(fù)雜手勢的監(jiān)聽,從此可以釋放雙手,來創(chuàng)造更多復(fù)雜的事件讓用戶更加順滑的使用了。