一、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:
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螢幕坐标系如下圖(左)
(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方向正好相反