멀티터치 동작은 포인터 (손가락) 여러 개가 동시에 화면을 탭하는 것을 말합니다. 이 문서에서는 여러 포인터가 개입된 동작을 감지하는 방법을 설명합니다.
여러 포인터 추적하기
여러 포인터가 동시에 화면을 탭하면 시스템에서 다음과 같은 터치 이벤트가 생성됩니다.
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, UP, CANCEL 작업은 전체 동작에 적용됩니다. 예를 들어 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) } ... }
자바
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 -> "" } }
자바
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 ""; }
추가 리소스
입력 이벤트와 관련된 자세한 내용은 다음 참조를 참고하세요.