天天看點

Android事件處理之多點觸摸與手勢識别

一、muilti-touch 雙指縮放的實作探索:

首先要實作ontouchlistener接口,然後重寫方法:

從這個方法中我們就可以擷取實作兩指縮放功能的全部資訊。

view v是觸發事件的源,motionevent event即一個觸摸事件。對螢幕的幾乎所有操作都會觸發事件,如點選、放開、滑動等。

不同的事件在motionevent中有不同的id,我們可以根據event.getaction() & motionevent.action_mask的結果來判斷是何種事件。

有如下事件使我們要用到的:

motionevent.action_down:在第一個點被按下時觸發

motionevent.action_up:當螢幕上唯一的點被放開時觸發

motionevent.action_pointer_down:當螢幕上已經有一個點被按住,此時再按下其他點時觸發。

motionevent.action_pointer_up:當螢幕上有多個點被按住,松開其中一個點時觸發(即非最後一個點被放開時)。

motionevent.action_move: 當有點在螢幕上移動時觸發。值得注意的是,由于它的靈敏度很高,而我們的手指又不可能完全靜止(即使我們感覺不到移動,但其實我們的手指也在不停地抖 動),是以實際的情況是,基本上隻要有點在螢幕上,此事件就會一直不停地被觸發。

舉 例子來說:當我們放一個食指到螢幕上時,觸發action_down事件;再放一個中指到螢幕上,觸發action_pointer_down事件;此時 再把食指或中指放開,都會觸發action_pointer_up事件;再放開最後一個手指,觸發action_up事件;而同時在整個過程 中,action_move事件會一直不停地被觸發。

event.getx(index)和event.gety(index)可以擷取到指定index點的坐标,是以當螢幕上有兩個點的時候,我們用如下方法來擷取兩點間的距離:

由以上事件觸發的原理,就可以根據被觸發的不同僚件來判斷目前螢幕上的點的個數:

然後在motionevent.action_move事件中,判斷點的個數,如果大于等于2,就計算兩點間的距離,如果距離增大就把圖檔放大,距離減少就把圖檔縮小。

于是代碼就成了:

經過檢驗,這種方法是能夠實作縮放效果的。

但是有了另外一個問題:就是由于action_move會因顫抖一直被觸發,而每次觸發的時候兩點間的距離也總會有細小的變化,是以運作之後隻要有兩點在螢幕上,就總會在放大或縮小字型。 

經過一番思考,我想出了一個控制其靈敏度的方法,即在case motionevent.action_move時判斷隻有當距離變化大于一定程度時才會更改字型大小:

另外縮放的方法也改成了按比例縮放,完整的zoomlistenter代碼:

這樣,基本算是能達到預期的效果了。

二、android 螢幕手勢滑動

android系統自帶一個gallery浏覽圖檔的應用,通過手指拖動時能夠非常流暢的顯示圖檔,使用者互動和體驗都很好。

是以本人研究了一下android的源碼後,寫了一個小demo:

Android事件處理之多點觸摸與手勢識别

1、基本原理

在 activity 中實作 ongesturelistener 的接口 onfling() 手勢事件,通過自定義的 view 繪制draw() 圖檔

2、activity

activity中,通過ontouchevent() 注冊 mygesture.ontouchevent(event)

接着實作接口ongesturelistener 的 onscroll()方法,給繼承自view的 flingview 的handlescroll()成員方法傳遞滑動參數,擷取滑動的x軸距離

接着實作接口ongesturelistener 的 onfling()方法,給繼承自view的 flingview 的onfling()成員方法傳遞滑動參數,擷取手勢的速度

3、flingview

flingview中,擷取來自activity中的手勢速度

在滑動過程中,通過實作view的draw()方法繪制圖檔,注意:此時需要同時繪制目前圖檔(擷取焦點)和下一張圖檔(即将擷取焦點)共兩張圖檔

在滑動圖檔結束後,需要做滑動動畫後的處理,重新設定目前圖檔和目前圖檔的上一張和下一張的狀态,為下次滑動做準備

4、手勢坐标介紹

本示例中,用到了ongesturelistener接口的onscroll()和onfling()方法,涉及到了android系統坐标及觸摸motionevent e1和e2、速度velocityx、velocityy等值

android螢幕坐标系如下圖(左)

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的水準距離

distancey,是前後兩次call的y距離,不是e2與e1的垂直距離

具體數值的方向,請詳見上圖(中)

(3)onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) 

velocityx,是x軸的每秒速度

velocityy,是y軸的每秒速度

具體數值的方向,請詳見上圖(右)

仔細觀察可以發現:velocityx、velocityy的方向與distancex、distancey方向正好相反