멀티 터치 동작은 여러 포인터 (손가락)가 동시에 화면을 탭하는 것입니다. 이 문서에서는 여러 포인터와 관련된 동작을 감지하는 방법을 설명합니다.
여러 포인터 추적하기
여러 포인터가 동시에 화면을 탭하면 시스템은 다음과 같은 터치 이벤트를 생성합니다.
ACTION_DOWN
: 첫 번째 포인터가 화면을 탭할 때 전송됩니다. 이 이벤트가 동작을 시작합니다. 이 포인터의 포인터 데이터는 항상MotionEvent
의 색인0
에 있습니다.ACTION_POINTER_DOWN
: 첫 번째 포인터 이후 추가 포인터가 화면으로 들어올 때 전송됩니다.getActionIndex()
를 사용하여 방금 다운된 포인터의 색인을 가져올 수 있습니다.ACTION_MOVE
: 여러 포인터가 포함된 동작에서 변경이 발생할 때 전송됩니다.ACTION_POINTER_UP
: 기본이 아닌 포인터가 위로 올라갈 때 전송됩니다.getActionIndex()
를 사용하여 방금 위로 올라온 포인터의 색인을 가져올 수 있습니다.ACTION_UP
: 마지막 포인터가 화면 밖으로 나갈 때 전송됩니다.ACTION_CANCEL
: 모든 포인터를 포함한 전체 동작이 취소되었음을 나타냅니다.
시작 및 종료 동작
동작은 ACTION_DOWN
이벤트로 시작하여 ACTION_UP
또는 ACTION_CANCEL
이벤트로 끝나는 일련의 이벤트입니다. 한 번에 한 가지 동작만 활성화됩니다. DOWN, MOVE, 위쪽, 취소 작업은 전체 동작에 적용됩니다. 예를 들어 ACTION_MOVE
가 있는 이벤트는 해당 시점의 모든 포인터가 이동함을 나타낼 수 있습니다.
포인터 추적하기
포인터의 색인과 ID를 사용하여 MotionEvent
내에서 개별 포인터 위치를 추적합니다.
- 색인:
MotionEvent
는 포인터 정보를 배열에 저장합니다. 포인터의 색인은 이 배열 내에서 포인터의 위치입니다. 대부분의MotionEvent
메서드는 포인터 ID가 아닌 매개변수로 포인터 색인을 사용합니다. - ID: 각 포인터에는 터치 이벤트 전체에서 지속성을 유지하는 ID 매핑도 있어 전체 동작에서 개별 포인터를 추적할 수 있습니다.
개별 포인터는 모션 이벤트 내에 정의되지 않은 순서로 표시됩니다. 따라서 포인터의 색인은 이벤트에서 다음 이벤트로 변경될 수 있지만, 포인터의 포인터 ID는 포인터가 활성 상태를 유지하는 한 일정하게 유지됩니다. getPointerId()
메서드를 사용하면 포인터의 ID를 획득하여 동작의 모든 후속 모션 이벤트에서 포인터를 추적할 수 있습니다. 그런 다음, 연속 모션 이벤트에 findPointerIndex()
메서드를 사용하여 해당 모션 이벤트에서 지정된 포인터 ID의 포인터 색인을 가져옵니다.
예:
Kotlin
private var mActivePointerId: Int = 0 override fun onTouchEvent(event: MotionEvent): Boolean { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0) // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. val (x: Float, y: Float) = event.findPointerIndex(mActivePointerId).let { pointerIndex -> // Get the pointer's current position. event.getX(pointerIndex) to event.getY(pointerIndex) } ... }
Java
private int mActivePointerId; public boolean onTouchEvent(MotionEvent event) { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0); // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. int pointerIndex = event.findPointerIndex(mActivePointerId); // Get the pointer's current position. float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); ... }
여러 터치 포인터를 지원하려면 개별 ACTION_POINTER_DOWN
및 ACTION_DOWN
이벤트 시간에 ID를 사용하여 모든 활성 포인터를 캐시하면 됩니다. ACTION_POINTER_UP
및 ACTION_UP
이벤트에서 캐시에서 포인터를 삭제합니다. 이러한 캐시된 ID는 다른 작업 이벤트를 올바르게 처리하는 데 유용합니다. 예를 들어 ACTION_MOVE
이벤트를 처리할 때 캐시된 각 활성 포인터 ID의 색인을 찾고 getX()
및 getY()
함수를 사용하여 포인터의 좌표를 검색한 다음 이 좌표를 캐시된 좌표와 비교하여 이동한 포인터를 확인합니다.
getActionIndex()
함수는 ACTION_POINTER_UP
및 ACTION_POINTER_DOWN
이벤트에만 사용합니다. 이 함수는 항상 0
를 반환하므로 ACTION_MOVE
이벤트와 함께 사용하지 마세요.
작업 MotionEvent
개 가져오기
getActionMasked()
메서드 또는 호환성 버전 MotionEventCompat.getActionMasked()
을 사용하여 MotionEvent
의 작업을 검색합니다. 이전 getAction()
메서드와 달리 getActionMasked()
는 여러 포인터와 함께 작동하도록 설계되었습니다. 포인터 인덱스 없이 작업을 반환합니다. 포인터 색인이 유효한 작업의 경우 다음 스니펫과 같이 getActionIndex()
를 사용하여 작업과 연결된 포인터의 색인을 반환합니다.
Kotlin
val (xPos: Int, yPos: Int) = MotionEventCompat.getActionMasked(event).let { action -> Log.d(DEBUG_TAG, "The action is ${actionToString(action)}") // Get the index of the pointer associated with the action. MotionEventCompat.getActionIndex(event).let { index -> // The coordinates of the current screen contact, relative to // the responding View or Activity. MotionEventCompat.getX(event, index).toInt() to MotionEventCompat.getY(event, index).toInt() } } if (event.pointerCount > 1) { Log.d(DEBUG_TAG, "Multitouch event") } else { // Single touch event. Log.d(DEBUG_TAG, "Single touch event") } ... // Given an action int, returns a string description. fun actionToString(action: Int): String { return when (action) { MotionEvent.ACTION_DOWN -> "Down" MotionEvent.ACTION_MOVE -> "Move" MotionEvent.ACTION_POINTER_DOWN -> "Pointer Down" MotionEvent.ACTION_UP -> "Up" MotionEvent.ACTION_POINTER_UP -> "Pointer Up" MotionEvent.ACTION_OUTSIDE -> "Outside" MotionEvent.ACTION_CANCEL -> "Cancel" else -> "" } }
Java
int action = MotionEventCompat.getActionMasked(event); // Get the index of the pointer associated with the action. int index = MotionEventCompat.getActionIndex(event); int xPos = -1; int yPos = -1; Log.d(DEBUG_TAG,"The action is " + actionToString(action)); if (event.getPointerCount() > 1) { Log.d(DEBUG_TAG,"Multitouch event"); // The coordinates of the current screen contact, relative to // the responding View or Activity. xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } else { // Single touch event. Log.d(DEBUG_TAG,"Single touch event"); xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } ... // Given an action int, returns a string description public static String actionToString(int action) { switch (action) { case MotionEvent.ACTION_DOWN: return "Down"; case MotionEvent.ACTION_MOVE: return "Move"; case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down"; case MotionEvent.ACTION_UP: return "Up"; case MotionEvent.ACTION_POINTER_UP: return "Pointer Up"; case MotionEvent.ACTION_OUTSIDE: return "Outside"; case MotionEvent.ACTION_CANCEL: return "Cancel"; } return ""; }
추가 리소스
입력 이벤트와 관련된 자세한 내용은 다음 참조를 확인하세요.