Android 手勢(shì)處理
作為忠實(shí)的 Android 系統(tǒng)用戶(hù),你應(yīng)該會(huì)經(jīng)常用到各種手勢(shì):點(diǎn)擊、長(zhǎng)按、雙擊、縮放、滑動(dòng)、拖拽、返回等等,可以說(shuō)豐富的手勢(shì)可以讓用戶(hù)更加簡(jiǎn)潔方便的使用 App,甚至直接影響到 App 的使用體驗(yàn)。這些手勢(shì)都是系統(tǒng)為我們提供的操作方式,今天來(lái)一起看看如何捕捉用戶(hù)的手勢(shì)輸入。
1 手勢(shì)檢測(cè)工具
在前面的章節(jié)我們講到過(guò)觸摸事件:onTouch(),它是一切手勢(shì)的開(kāi)始,所以根據(jù)onTouch
的幾種事件類(lèi)型我們可以判斷出用戶(hù)的各種手勢(shì),但是對(duì)于一些相對(duì)復(fù)雜的手勢(shì)(比如縮放、旋轉(zhuǎn)、雙擊等)判斷起來(lái)會(huì)比較麻煩。不過(guò)這些都不用擔(dān)心Android 系統(tǒng)為我們提供了一個(gè)叫GestureDetector
的工具類(lèi),通過(guò)它我們可以輕松的接收到用戶(hù)的各種復(fù)雜手勢(shì)。
GestureDetector
的使用方法非常簡(jiǎn)單,首先創(chuàng)建一個(gè)類(lèi)繼承自GestureDetector.SimpleOnGestureListener
,然后覆寫(xiě)其中需要監(jiān)聽(tīng)的事件方法,如下:
GestureDetector mGesture;
mGesture = new GestureDetector(this, new Gesture());
class Gesture extends GestureDetector.SimpleOnGestureListener{
public boolean onSingleTapUp(MotionEvent ev) {
// 處理單擊事件
}
public void onLongPress(MotionEvent ev) {
// 處理長(zhǎng)按
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// 處理滑動(dòng)手勢(shì)
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// 處理快速滾動(dòng)
}
}
2 GestureListener 相關(guān)事件
Gesture 支持很多復(fù)雜的手勢(shì)處理,基本上處理手勢(shì)用它就沒(méi)錯(cuò)了。這里挑幾個(gè)最常見(jiàn)的進(jìn)行詳細(xì)的講解,其余的也大同小異。
- onDown: 觸摸事件,同
onTouch
事件當(dāng)中的ACTION_DOWN
,所有手勢(shì)的起點(diǎn) - onSingleTapUp: 單擊
- onLongPress: 長(zhǎng)按
- onScroll: 滾動(dòng)
- onFling: 手指快速滾動(dòng),并離開(kāi)屏幕,在屏幕繼續(xù)滾動(dòng)的時(shí)候觸發(fā)
3 手勢(shì)的處理方式
在寫(xiě)好了第 1 小節(jié)的代碼之后,關(guān)鍵就是去實(shí)現(xiàn)事件處理代碼了,點(diǎn)擊、長(zhǎng)按等事件都比較好理解,這里以縮放手勢(shì)為例講解一下具體的手勢(shì)處理邏輯。
3.1 縮放處理工具類(lèi)
縮放的手勢(shì)處理是通過(guò)ScaleGestureDetector
來(lái)實(shí)現(xiàn)的,首先創(chuàng)建一個(gè)ScaleGestureDetector
:
ScaleGestureDetector scaleGestureDetector;
scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
構(gòu)造器需要傳入兩個(gè)參數(shù),一個(gè)是上下文 context,一個(gè)是縮放時(shí)間監(jiān)聽(tīng)器。所以,在此之前我們還需要?jiǎng)?chuàng)建一個(gè)ScaleListener
,然后覆寫(xiě)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 手勢(shì)處理中常用的系統(tǒng)方法
在處理手勢(shì)的過(guò)程中,我們還會(huì)調(diào)用一些系統(tǒng)方法來(lái)輔助完成事件處理,主要有以下幾個(gè):
- getEventTime():
獲取事件發(fā)生的時(shí)間戳 - getFocusX():
獲取當(dāng)前手勢(shì)焦點(diǎn)的 X 軸坐標(biāo) - getFocusY():
獲取當(dāng)前手勢(shì)焦點(diǎn)的 Y 軸坐標(biāo) - getTimeDelta():
獲取兩次縮放時(shí)間的時(shí)間差 - isInProgress():
判斷當(dāng)前是否正處理縮放過(guò)程中 - onTouchEvent(MotionEvent event):
接收系統(tǒng)觸摸事件,并分發(fā)到相應(yīng)的監(jiān)聽(tīng)器中
4 手勢(shì)處理示例
本節(jié)通過(guò)GestureDetector
完成一個(gè)類(lèi)似微信聊天中的大圖縮放功能,即通過(guò)雙指往外或者向內(nèi)的手勢(shì)來(lái)控制圖片的放大、縮小。
4.1 編寫(xiě)布局文件
布局文件非常簡(jiǎn)單,核心就是一個(gè) ImageView,用來(lái)承載我們縮放的目標(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="手勢(shì)處理示例"
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 手勢(shì)處理邏輯編寫(xiě)
手勢(shì)處理基本遵循上述邏輯,分為 4 步:
- 第一步: 首先創(chuàng)建一個(gè)
ScaleListener
,覆寫(xiě)onScale
方法來(lái)接收縮放手勢(shì); - 第二步: 然后創(chuàng)建
ScaleGestureDetector
,構(gòu)造器傳入 context 對(duì)象及剛剛創(chuàng)建的ScaleListener
對(duì)象; - 第三步: 接著覆寫(xiě)
onTouchEvent(MotionEvent ev)
,調(diào)用 ScaleGestureDetector 的onTouchEvent()
方法,傳入 MotionEvent,這樣就把觸摸事件傳遞給了ScaleGestureDetector
,后續(xù)的整個(gè)縮放手勢(shì)就全權(quán)交給ScaleGestureDetector
來(lái)處理。 - 第四步: 最后我們只需要在
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)建縮放手勢(shì)檢測(cè)器ScaleGestureDetector,用于檢測(cè)縮放手勢(shì)
mDetector = new ScaleGestureDetector(this, new ScaleListener());
}
// 第3步:覆寫(xiě)onTouchEvent,將觸摸事件傳遞給ScaleGestureDetector
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}
// 第1步:創(chuàng)建縮放監(jiān)聽(tīng)器,用于接收縮放事件
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
// 第4步:實(shí)現(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)滑動(dòng),就可以看到“照騙”會(huì)跟隨我們的手勢(shì)而放大/縮小,整個(gè)流程非常順滑無(wú)污染,歡迎自行編譯體驗(yàn)。
溫馨提示: 照騙高清,請(qǐng)謹(jǐn)慎放大
5 小結(jié)
本節(jié)介紹了一個(gè)非常強(qiáng)大的手勢(shì)處理工具——GestureDetector,如果不使用它,我們需要自行監(jiān)聽(tīng)onTouch
事件,然后結(jié)合“DOWN”、“MOVE”、“UP”等等各種不同的 onTouch 事件組合起來(lái)才能檢測(cè)出一些復(fù)雜的手勢(shì),這一切 GestureDetector 都幫助我們實(shí)現(xiàn)了。學(xué)完這一章,我們只需要按照幾個(gè)簡(jiǎn)單的步驟就可以進(jìn)行復(fù)雜手勢(shì)的監(jiān)聽(tīng),從此可以釋放雙手,來(lái)創(chuàng)造更多復(fù)雜的事件讓用戶(hù)更加順滑的使用了。