日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转】android手势处理揭秘

發(fā)布時間:2025/5/22 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】android手势处理揭秘 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

當(dāng)滑動(fling)比移動(scroll)有更高的效率時,為什么要讓用戶使用scroll操作呢?在面積很小而數(shù)據(jù)又很多的移動設(shè)備上,要顯示遠在后面的那些內(nèi)容scroll是很困難的,這種情況下fling更適合。

注:scroll表示手指滑動多少距離,界面跟著顯示多少距離,而fling是根據(jù)你的滑動方向與輕重,還會自動滑動一段距離。

filing 手勢在android交互設(shè)計中應(yīng)用非常廣泛:電子書的滑動翻頁、ListView滑動刪除item、滑動解鎖等。所以如何檢測用戶的fling手勢是非 常重要的。但是我們?nèi)绾潍@得fling消息呢?如何知道fling的方向,從哪里開始從哪里結(jié)束?又如何確定當(dāng)前手勢是fling 而不是scroll?

在我最近的項目Room5中就面臨這樣的問題,這是一個已經(jīng)有了的ios項目,現(xiàn)在要做一個android版本。

在 我們處理滑動動畫之前,我們需要檢測fling事件,對初學(xué)者而言,這要比看上去復(fù)雜一些。這是因為touch、scroll、fling三個事件之間并 沒有明顯的界限。scroll總是發(fā)生在fling之前,而touch總是發(fā)生在scroll之前,滑動屏幕(fling)總是需要先觸摸屏幕 (touch)并且在屏幕上移動(scroll)。我們?nèi)绾沃阑瑒?#xff08;fling)沒有被touch事件攔截呢?答案是使用幾個關(guān)于手勢 (gesture)處理的類。

我寫了一個演示這幾個類是如何配合使用的例子程序,你可以在這里得到完整的源碼:https://github.com/ericacooksey/FlingDemo 這個demo描述了捕捉fling事件的整個過程。下面是運行apk之后初始界面的截圖:

當(dāng)接收到touch,scroll或者fling事件,事件的名稱會顯示在界面上,最近發(fā)生的顯示在最上面。下面是某一次從上往下劃動(fling)時,界面上輸出的文字:

這幅圖給了你關(guān)于事件流的一個大概認識:view收到了好幾個scroll 事件,每個scroll事件之前都伴隨著一個touch事件。scroll事件過程中y軸方向上的速度飛快增長,直到最終fling事件被觸發(fā)。讓我們來看看關(guān)鍵代碼, 這里。

首 先,我們實現(xiàn)了View.OnTouchListener來攔截view的touch事件。我這里暫時省略了對滑動速度追蹤的代碼(省略號),我們將在后 面討論。這里主要是實現(xiàn)了touch事件觸發(fā)的時候?qū){(diào)用的回到方法,將此方法注冊給相應(yīng)的view(這里為TextView),下面是代碼片段。

1 mTouchListener = new VelocityTrackingTouchListener(); 2 // Initialize the TextView which will be used to display the logged events 3 mTextView = (TextView) findViewById(R.id.mytextview); 4 mTextView.setOnTouchListener(mTouchListener); 5 private class VelocityTrackingTouchListener implements View.OnTouchListener { 6 @Override 7 public boolean onTouch(View view, MotionEvent motionEvent) { 8 ...... 9 mGestureDetector.onTouchEvent(motionEvent); 10 return true; 11 } 12 }

mGestureDetector 是GestureDetector的實例。onTouch回調(diào)方法在將事件派發(fā)給view之前接收到了touch事件。任何可能跟touch事件相關(guān)的事 件(比如Click)都會被這個回調(diào)方法攔截。我們將touch事件交給GestureDetector,因此這里的作用其實就是在將touch事件傳遞 下去之前,將MotionEvent傳遞給GestureDetector的onTouchEvent方法,先判斷當(dāng)前到底是什么手勢。下面是聲明 GestureDetector變量的代碼片段:

1 // Instantiate a gesture listener to consume scroll and fling events 2 FlingDetector flingDetector = new FlingDetector(); 3 // Pass the FlingDetector to mGestureDetector to receive the appropriate callbacks 4 mGestureDetector = new GestureDetector(this, flingDetector);

?

其中FlingDetector是我們繼承自SimpleOnGestureListener的一個類。使用SimpleOnGestureListener的好處是它完成了所有對GestureDetector.OnGestureListener所有接口的空實現(xiàn),因此我們只需重寫需要的回調(diào)方法。

1 private class FlingDetector extends GestureDetector.SimpleOnGestureListener { 2 public FlingDetector() { 3 super(); 4 } 5 @Override 6 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 7 float velocityY) { 8 updateText("in onFling"); 9 return true; 10 } 11 @Override 12 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 13 updateText(String.format("onScroll velocity = (%f, %f)", mTouchListener.xVelocity, mTouchListener.yVelocity)); 14 return false; 15 } 16 }

?

作為總結(jié),下面是對上面一系列過程的回顧:

(1)view所注冊的OnTouchListener攔截了touch事件。

(2)OnTouchListener的回調(diào)方法onTouch(View view, MotionEvent motionEvent)將MotionEvent傳遞給了GestureDetector。

(3)實現(xiàn)一個OnGestureListener,并將他注冊給GestureDetector,這樣OnGestureListener中處理具體手勢的回調(diào)方法就能被觸發(fā)。

注 意OnGestureListener的每個方法都會返回一個boolean值,這個返回值表示當(dāng)前方法結(jié)束之后,MotionEvent是否被“消費” 掉,也就是說是否繼續(xù)傳遞下去,true表示被消費掉,反之則沒有,可以繼續(xù)傳遞?;叵肷厦嫖覀兲岬降膄iling發(fā)生在scroll之后,scroll 發(fā)生在touch之后,而我們希望接收到fling手勢,因此我們在onScroll中返回false,在fling中返回true。

但是 現(xiàn)在問題是如果我們希望一個view既可以scroll也可以fling怎么辦?比如一個賬單界面我們希望sroll查看賬單而用fling操作表示 swipe-to-pay。如果你參考上面的fling事件的截圖會發(fā)現(xiàn)onScroll在onFLing觸發(fā)之前發(fā)生了5次。因此如果我們響應(yīng) onScroll事件,那么用戶在fling操作的時候會感到不自然,因為scroll的對我們預(yù)期的交互產(chǎn)生了干擾。

我們可以直接忽略掉 scroll,將onScroll中的實現(xiàn)留為空,但是這樣的話,如果用戶手指慢慢滑動查看后面的內(nèi)容就得不到響應(yīng)。最好是能在scroll的時候判斷這 個scroll是否會導(dǎo)致fling的發(fā)生。這種情況下android的VelocityTracker 就派上用場了。先來瞄一眼scroll的時候的手勢輸出日志:

讓我們將這張圖中(只有scroll事件的截圖)y方向上的速度和上一張圖(產(chǎn)生了fling事件的截圖)y方向上的速度做一個對比。之所以用y速度是因為兩次實驗中我們都是從上到下的滑動。

?

Scroll y-velocityFling y-velocity
6530085
14023359
42413787
66010414
8477449

如你所見, 產(chǎn)生了fling事件的滾動(scroll)事件中y-velocity要比沒有產(chǎn)生fling的滾動(scroll)高很多。我們在OnTouchListener的實現(xiàn)中跟蹤速度,每收到一個觸摸事件就將之添加給 mVelocityTracker

1 switch (action) { 2 case MotionEvent.ACTION_DOWN: 3 if (mVelocityTracker == null) { 4 // Retrieve a new VelocityTracker object to watch the velocity of a motion. 5 mVelocityTracker = VelocityTracker.obtain(); 6 } else { 7 // Reset the velocity tracker back to its initial state. 8 mVelocityTracker.clear(); 9 } 10 // Add a user's movement to the tracker. 11 mVelocityTracker.addMovement(motionEvent); 12 break; 13 case MotionEvent.ACTION_MOVE: 14 mVelocityTracker.addMovement(motionEvent); 15 // When you want to determine the velocity, call 16 // computeCurrentVelocity(). Then call getXVelocity() 17 // and getYVelocity() to retrieve the velocity for each pointer ID. 18 mVelocityTracker.computeCurrentVelocity(1000); 19 // Log velocity of pixels per second 20 xVelocity = mVelocityTracker.getXVelocity(pointerId); 21 yVelocity = mVelocityTracker.getYVelocity(pointerId); 22 break; 23 case MotionEvent.ACTION_CANCEL: 24 // Return a VelocityTracker object back to be re-used by others. 25 mVelocityTracker.recycle(); 26 break; 27 }

?

然后再將觸摸事件傳遞給FlingDetector去分析,在FlingDetector打印出mVelocityTracker的速度以及對應(yīng)的狀態(tài)(scroll還是fling),經(jīng)過多次實驗可以找到一個合理的決定scroll是否會導(dǎo)致fling的臨界值。從事判斷是否相應(yīng)onScroll。

轉(zhuǎn)載于:https://www.cnblogs.com/liangstudyhome/p/4170487.html

總結(jié)

以上是生活随笔為你收集整理的【转】android手势处理揭秘的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。