Android 雙擊單擊事件監(jiān)聽手勢檢測GestureDetector原理及實(shí)現(xiàn)

app我們常用的手勢有很多的地方罩润,比如右滑關(guān)閉界面等荠察。手勢控制分為觸發(fā)動(dòng)作(Touch Mechanics蚤霞,用戶手指在屏幕上如何動(dòng)作)和觸發(fā)行為(Touch Activities挑豌,界面上特定動(dòng)作在特定情境下引發(fā)的結(jié)果)安券。這是因?yàn)橥瑯拥挠|發(fā)動(dòng)作(如單次觸擊)在不同情境下可能會(huì)帶來不同的結(jié)果(如輕觸,取消氓英,開啟/關(guān)閉指示)侯勉,同樣單次觸發(fā)行為(如放大)可能是由多種觸發(fā)動(dòng)作(如捏放,雙次觸擊铝阐,雙次觸擊拖拽等)實(shí)現(xiàn)址貌。

? ? 一般情況下,我們知道View類有個(gè)View.OnTouchListener內(nèi)部接口,通過重寫他的onTouch(View v, MotionEvent event)方法练对,我們可以處理一些touch事件余舶,但是這個(gè)方法太過簡單,如果需要處理一些復(fù)雜的手勢锹淌,用這個(gè)接口就會(huì)很麻煩(因?yàn)槲覀円约焊鶕?jù)用戶觸摸的軌跡去判斷是什么手勢)。

? ? Android sdk給我們提供了GestureDetector類赠制,通過這個(gè)類我們可以識別很多的手勢赂摆,主要是通過他的onTouchEvent(event)方法完成了不同手勢的識別。雖然他能識別手勢钟些,但是不同的手勢要怎么處理烟号,應(yīng)該是提供給程序員實(shí)現(xiàn)的。

一.GestureDetector簡介

1.組成

GestureDetector類用來識別觸摸屏的各種手勢政恍,它包含了兩個(gè)接口和一個(gè)內(nèi)部類:

接口:

OnGestureListener:用來監(jiān)聽手勢事件(6種)汪拥。

OnDoubleTapListener:用來監(jiān)聽雙擊事件。

內(nèi)部類:

SimpleOnGestureListener:用來監(jiān)聽所有的手勢篙耗。實(shí)際上它實(shí)現(xiàn)了上述兩個(gè)接口迫筑,不過方法體是空的,需要我們自己寫宗弯。我們可以繼承這個(gè)類脯燃,重寫里面的方法進(jìn)行手勢處理。

2.構(gòu)造

GestureDetector gestureDetector = new GestureDetector(GestureDetector.OnGestureListener listener);

GestureDetector gestureDetector = new GestureDetector(Context context,GestureDetector.OnGestureListener listener);

GestureDetector gestureDetector = new GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener);

3.方法

(1)onTouchEvent(MotionEvent ev) 分析捕捉到的觸摸事件觸發(fā)相應(yīng)的回調(diào)函數(shù)

(2)setIsLongpressEnabled(boolean isLongpressEnabled) 設(shè)置“長按”是否可用

(3)setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener) 設(shè)置雙擊監(jiān)聽器

4.使用

流程:

首先蒙保,系統(tǒng)捕捉屏幕的觸摸事件(onTouchListener),這時(shí)還未涉及具體手勢辕棚,只是簡單地捕捉到觸摸。

接著邓厕,在onTouch()方法中調(diào)用GestureDetector的onTouchEvent()方法逝嚎,將捕捉到的MotionEvent交給GestureDetector來處理

最后,還需要實(shí)現(xiàn)抽象方法详恼。

可根據(jù)需要選擇:

重寫OnGestureListener并通過構(gòu)造函數(shù)傳入gestureDetector

重寫OnDoubleTapListener并通過GestureDetector.setOnDoubleTapListener方法傳入gestureDetector

重寫SimpleOnGestureListener并通過構(gòu)造函數(shù)傳入gestureDetector

實(shí)現(xiàn):

注:不要注重我寫的類是什么類补君,要注重實(shí)現(xiàn)方法自定義view和activity中都可以,根據(jù)需要繼承上面三種listener昧互,傳入構(gòu)造函數(shù)即可赚哗;

public class TestDemo{

Context context;

public TestDemo(Context context){

this.context = context;

}

private GestureDetectordetector;

private void initView(){

detector =new GestureDetector(context, new MySimple());

detector =new GestureDetector(context, new MyGesture());

detector =new GestureDetector(context, new MyDoubleTap());

setOnTouchListener((v, event) -> {

// 事件監(jiān)聽交給手勢類來處理

detector.onTouchEvent(event);

return true;

});

}

//與上面二選一

@Override

public boolean onTouchEvent(MotionEvent event) {

return detector.onTouchEvent(event);

}

// 手勢監(jiān)聽器類SimpleOnGestureListener

? ? private class MySimple extends GestureDetector.SimpleOnGestureListener {

? ? ? ? @Override

? ? ? ? public boolean onSingleTapUp(MotionEvent e) {//一次單獨(dú)的輕擊抬起操作,也就是輕擊一下屏幕,立刻抬起來硅堆,才會(huì)有這個(gè)觸發(fā)屿储;如果除了Down以外還有其它操作,那就不再是Single操作了,所以也就不會(huì)觸發(fā)這個(gè)事件

? ? ? ? ? ? return super.onSingleTapUp(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public void onLongPress(MotionEvent e) {//長按事件;

? ? ? ? ? ? super.onLongPress(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {//在屏幕上拖動(dòng)事件,只要手指移動(dòng)就會(huì)執(zhí)行渐逃,無論是用手拖動(dòng)view够掠,或者是以拋的動(dòng)作滾動(dòng),都會(huì)多次觸發(fā),這個(gè)方法在ACTION_MOVE動(dòng)作發(fā)生時(shí)就會(huì)觸發(fā)他不會(huì)執(zhí)行MotionEvent.ACTION_UP,通常用來實(shí)現(xiàn)放大縮小和移動(dòng)茄菊。

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {//滑動(dòng)屏幕疯潭,用戶按下觸摸屏赊堪、快速移動(dòng)后松開,由1個(gè)MotionEvent ACTION_DOWN, 多個(gè)ACTION_MOVE, 1個(gè)ACTION_UP觸發(fā);是個(gè)甩的動(dòng)作竖哩,這個(gè)甩的動(dòng)作是在一個(gè)MotionEvent.ACTION_UP(手指抬起)發(fā)生時(shí)執(zhí)行,通常用來實(shí)現(xiàn)翻頁效果

? ? ? ? ? ? return super.onFling(e1, e2, velocityX, velocityY);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public void onShowPress(MotionEvent e) {//down事件發(fā)生而move或則up還沒發(fā)生前觸發(fā)該事件哭廉;

? ? ? ? ? ? super.onShowPress(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onDown(MotionEvent e) {//down事件用戶按下屏幕

? ? ? ? ? ? return super.onDown(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onDoubleTap(MotionEvent e) {//雙擊事件

? ? ? ? ? ? return super.onDoubleTap(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onDoubleTapEvent(MotionEvent e) {//雙擊間隔中還發(fā)生其他的動(dòng)作。通知DoubleTap手勢中的事件相叁,包含down遵绰、up和move事件(這里指的是在雙擊之間發(fā)生的事件,例如在同一個(gè)地方雙擊會(huì)產(chǎn)生DoubleTap手勢增淹,而在DoubleTap手勢里面還會(huì)發(fā)生down和up事件椿访,這兩個(gè)事件由該函數(shù)通知)

? ? ? ? ? ? return super.onDoubleTapEvent(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onSingleTapConfirmed(MotionEvent e) {//單擊事件。用來判定該次點(diǎn)擊是SingleTap而不是DoubleTap虑润,如果連續(xù)點(diǎn)擊兩次就是DoubleTap手勢成玫,如果只點(diǎn)擊一次,系統(tǒng)等待一段時(shí)間后沒有收到第二次點(diǎn)擊則判定該次點(diǎn)擊為SingleTap而不是DoubleTap拳喻,然后觸發(fā)SingleTapConfirmed事件哭当。

? ? ? ? ? ? return super.onSingleTapConfirmed(e);

? ? ? ? }

? ? }

// 手勢監(jiān)聽器類GestureListener

? ? private class MyGesture extends GestureDetector.OnGestureListener{

? ? ? ? @Override

? ? ? ? public boolean onDown(MotionEvent e) {//down事件用戶按下屏幕

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? @Override

? ? ? ? public void onShowPress(MotionEvent e) {//down事件發(fā)生瞬間而move或則up還沒發(fā)生前觸發(fā)該事件;

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onSingleTapUp(MotionEvent e) {//一次單獨(dú)的輕擊抬起操作,也就是輕擊一下屏幕冗澈,立刻抬起來荣病,才會(huì)有這個(gè)觸發(fā);如果除了Down以外還有其它操作,那就不再是Single操作了,所以也就不會(huì)觸發(fā)這個(gè)事件渗柿;

? ? ? ? ? ? return super.onSingleTapUp(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {//在屏幕上拖動(dòng)事件,只要手指移動(dòng)就會(huì)執(zhí)行个盆,無論是用手拖動(dòng)view,或者是以拋的動(dòng)作滾動(dòng)朵栖,都會(huì)多次觸發(fā),這個(gè)方法在ACTION_MOVE動(dòng)作發(fā)生時(shí)就會(huì)觸發(fā)他不會(huì)執(zhí)行MotionEvent.ACTION_UP,通常用來實(shí)現(xiàn)放大縮小和移動(dòng)颊亮。

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? @Override

? ? ? ? public void onLongPress(MotionEvent e) {//長按事件,超過一定時(shí)長觸發(fā)該事件回調(diào)陨溅;

? ? ? ? ? ? super.onLongPress(e);

? ? ? ? }

? ? ? ? public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {//滑動(dòng)屏幕终惑,用戶按下觸摸屏、快速移動(dòng)后松開门扇,由1個(gè)MotionEvent ACTION_DOWN, 多個(gè)ACTION_MOVE, 1個(gè)ACTION_UP觸發(fā);是個(gè)甩的動(dòng)作雹有,這個(gè)甩的動(dòng)作是在一個(gè)MotionEvent.ACTION_UP(手指抬起)發(fā)生時(shí)執(zhí)行,通常用來實(shí)現(xiàn)翻頁效果

? ? ? ? ? ? return super.onFling(e1, e2, velocityX, velocityY);

? ? ? ? }

? ? }

// 手勢監(jiān)聽器類SimpleOnGestureListener

? ? private class MyDoubleTap extends GestureDetector.OnDoubleTapListener {

? ? ? ? @Override

? ? ? ? public boolean onDoubleTap(MotionEvent e) {//雙擊事件

? ? ? ? ? ? return super.onDoubleTap(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onDoubleTapEvent(MotionEvent e) {//雙擊間隔中還發(fā)生其他的動(dòng)作。通知DoubleTap手勢中的事件臼寄,包含down霸奕、up和move事件(這里指的是在雙擊之間發(fā)生的事件,例如在同一個(gè)地方雙擊會(huì)產(chǎn)生DoubleTap手勢吉拳,而在DoubleTap手勢里面還會(huì)發(fā)生down和up事件质帅,這兩個(gè)事件由該函數(shù)通知)

? ? ? ? ? ? return super.onDoubleTapEvent(e);

? ? ? ? }

? ? ? ? @Override

? ? ? ? public boolean onSingleTapConfirmed(MotionEvent e) {//單擊事件。用來判定該次點(diǎn)擊是SingleTap而不是DoubleTap,如果連續(xù)點(diǎn)擊兩次就是DoubleTap手勢煤惩,如果只點(diǎn)擊一次嫉嘀,系統(tǒng)等待一段時(shí)間后沒有收到第二次點(diǎn)擊則判定該次點(diǎn)擊為SingleTap而不是DoubleTap,然后觸發(fā)SingleTapConfirmed事件魄揉。

? ? ? ? ? ? return super.onSingleTapConfirmed(e);

? ? ? ? }

? ? }

}

關(guān)于onFling()和onScroll()的區(qū)別:

onFling()是甩剪侮,這個(gè)甩的動(dòng)作是在一個(gè)MotionEvent.ACTION_UP(手指抬起)發(fā)生時(shí)執(zhí)行,而onScroll()洛退,只要手指移動(dòng)就會(huì)執(zhí)行瓣俯。他不會(huì)執(zhí)行MotionEvent.ACTION_UP。onFling通常用來實(shí)現(xiàn)翻頁效果不狮,而onScroll通常用來實(shí)現(xiàn)放大縮小和移動(dòng)。

關(guān)于onSingleTapConfirmed和onSingleTapUp的一點(diǎn)區(qū)別: OnGestureListener有這樣的一個(gè)方法onSingleTapUp在旱,和onSingleTapConfirmed容易混淆摇零。二者的區(qū)別是:onSingleTapUp,只要手抬起就會(huì)執(zhí)行桶蝎,而對于onSingleTapConfirmed來說驻仅,如果雙擊的話,則onSingleTapConfirmed不會(huì)執(zhí)行

SimpleOnGestureListener是GestureDetector類的一個(gè)內(nèi)部類登渣,該類是static class噪服,也就是說它實(shí)際上是一個(gè)外部類∈ぜ耄可以在外部繼承這個(gè)類粘优,重寫里面的手勢處理方法。

1.OnDoubleTapListener是用來檢測鼠標(biāo)雙擊事件的

2.SimpleOnGestureListener實(shí)際上實(shí)現(xiàn)了OnGestureListener 和OnDoubleTapListener呻顽,所以它可以完成以上提到的所有手勢識別(9種)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雹顺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子廊遍,更是在濱河造成了極大的恐慌嬉愧,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喉前,死亡現(xiàn)場離奇詭異没酣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卵迂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門裕便,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人见咒,你說我怎么就攤上這事闪金。” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵哎垦,是天一觀的道長囱嫩。 經(jīng)常有香客問我,道長漏设,這世上最難降的妖魔是什么墨闲? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮郑口,結(jié)果婚禮上鸳碧,老公的妹妹穿的比我還像新娘。我一直安慰自己犬性,他們只是感情好瞻离,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乒裆,像睡著了一般套利。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鹤耍,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天肉迫,我揣著相機(jī)與錄音,去河邊找鬼稿黄。 笑死喊衫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杆怕。 我是一名探鬼主播族购,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼陵珍!你這毒婦竟也來了联四?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤撑教,失蹤者是張志新(化名)和其女友劉穎朝墩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伟姐,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡收苏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了愤兵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹿霸。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖秆乳,靈堂內(nèi)的尸體忽然破棺而出懦鼠,到底是詐尸還是另有隱情钻哩,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布肛冶,位于F島的核電站街氢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏睦袖。R本人自食惡果不足惜珊肃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馅笙。 院中可真熱鬧伦乔,春花似錦、人聲如沸董习。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽皿淋。三九已至招刹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沥匈,已是汗流浹背蔗喂。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工忘渔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留高帖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓畦粮,卻偏偏與公主長得像散址,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子宣赔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容