處理多點觸控手勢
多點觸控就是同時把一根以上的手指放在屏幕上。
再繼續往下以前需要補充一些名詞(弄清楚這些對理解下面的內容非常有用):
- 觸控手勢:就是把一根或者幾根手指放在屏幕上做各種動作,在保留一根手指的前提下,移動、拿起或者放下其余的手指。
- 觸控事件:在觸控手勢中,有手指移動或者離開屏幕的時候就會引發一系列的觸控事件。每引發一個事件就會出現一個
MotionEvent
。在這個事件中,包含說與的觸控數據。 - 觸控:手指碰到屏幕的時候就產生了一個觸控(pointer)。
一個觸控手勢包含一個或多個觸控事件。一個觸控事件包含一個或多個觸控。比如用兩個手指敲擊屏幕,會有一個MotionEvent.ACTION_DOWN
一個MotionEvent.ACTION_POINTER_DOWN
,點擊用力的話還會連續多個的MotionEvent.ACTION_MOVE
,最后出現MotionEvent.ACTION_UP
和MotionEvent.ACTION_POINTER_UP
。那么,“兩個手指敲擊屏幕”就是一個觸控手勢,順序依次出現的多個MotionEvent
就是觸控事件,每個觸控事件可以通過getActionIndex
方法獲得一個觸控點(Pointer)。
追蹤多個觸控點
多個手指同時放在屏幕上的時候會觸發以下的系統事件:
- ACTION_DOWN --第一個對屏幕的觸碰。這是多點觸控的開始。這個觸碰的而數據保存在index為0的
MotionEvent
中。 - ACTION_POINTER_DOWN--其他對屏幕的觸碰。觸碰事件的index可以用方法
getActionIndex()
獲取到。觸碰的數據保存在這個index指定的MotionEvent
中。 - ACTION_MOVE--放在屏幕上的任何一根手指移動的時候觸發。
- ACTION_POINTER_UP--第一個觸摸屏幕的手指以外的其他手指離開屏幕的時候觸發。
- ACTION_UP--當最后一根手指離開屏幕的時候觸發。
你可以通過觸碰事件的index或者ID來獲得事件MotionEvent
。
- Index: 一個
MotionEvent
存儲了幾根手指觸摸屏幕的每一個手指的觸碰數據。一般處理觸摸的是后都用index作為獲取MotionEvent
的依據,而不是觸碰ID。 - ID:整個多點觸摸事件過程中,每一個觸摸都有一個ID和整個觸摸匹配。
一個觸碰的index在MotionEvent
中可能發生改變的。而整個觸碰的ID是保持不變的,只要整個觸碰保持激活狀態。用getPointerId()
可以獲取整個手勢執行期間的每一個event里的觸碰數據。也可以通過findPointerIndex()
來根據一個觸控的ID來獲取這觸控在觸控事件中的index。比如:
var mActivePointerId: Int? = null
override fun onTouchEvent(event: MotionEvent?): Boolean {
mActivePointerId = event?.getPointerId(0)
// 其他的事件先不管...
// 用觸控ID獲得index,然后獲取位置數據
var pointerIndex = event?.findPointerIndex(mActivePointerId!!)
// 獲取觸控的當前位置
var x = event?.getX(pointerIndex!!)
var y = event?.getY(pointerIndex!!)
return true
}
獲取一個MotionEvent的Action
你應該使用getActionMasked()
(或者從兼容方面考慮的話用MotionEventCompat.getAtionMasked()
來獲取MotionEvent
的action。與getAction()
不同,getActionMasked()
就是被用來處理多點觸控的。這個方法的返回值不在包含觸控index的位數。你可以用getActonIndex()
來獲取觸控action的index。這些在后面詳細敘述。
注意:后面的例子用的是MotionEventCompat類。這個類在Support Library中。
你可以使用MotionEventCompat來獲得更多的平臺支持。MotionEventCompat不是用來代替MotionEvent的。
其實,這個類只是提供了一些靜態方法以方便使用。
override fun onTouchEvent(event: MotionEvent?): Boolean {
var action = MotionEventCompat.getActionMasked(event!!)
var index: Int = MotionEventCompat.getActionIndex(event!!)
var xPos = -1.0f
var yPos = -1.0f
Log.d(TAG, "The action is " + actionToSring(action))
if (event!!.pointerCount > 1) {
Log.d(TAG, "Mutipletouch event")
// 坐標系是相對于處理這個事件的View或者Activity的
xPos = MotionEventCompat.getX(event!!, index)
yPos = MotionEventCompat.getY(event!!, index)
} else {
//單點觸控
Log.d(TAG, "Single touch event")
xPos = MotionEventCompat.getX(event!!, index)
yPos = MotionEventCompat.getY(event!!, index)
}
return true
}
fun actionToSring(action: Int): String {
when (action) {
MotionEvent.ACTION_DOWN -> return "Down"
MotionEvent.ACTION_MOVE -> return "Move"
MotionEvent.ACTION_POINTER_DOWN -> return "Pointer down"
MotionEvent.ACTION_UP -> return "UP"
MotionEvent.ACTION_POINTER_UP -> return "Pointer up"
MotionEvent.ACTION_OUTSIDE -> return "Outside"
MotionEvent.ACTION_CANCEL -> return "Cancel"
}
return ""
}
原文是Google的文檔。但是文檔中的前提和一些概念的描述不足,會導致初學者理解出現偏差。我都加上了,我就是初學者。
代碼都是用Kotlin寫的,自從用了這個語言就再也不想用Java了。對于Java開發者理解Kotlin的代碼沒有什么太大的問題,Kotlin的可讀性更強一些。