다음을 통해 공유


멀티 터치 손가락 추적

이 항목에서는 여러 손가락에서 터치 이벤트를 추적하는 방법을 보여 줍니다.

멀티 터치 애플리케이션이 화면에서 동시에 이동할 때 개별 손가락을 추적해야 하는 경우가 있습니다. 일반적인 애플리케이션 중 하나는 손가락 페인트 프로그램입니다. 사용자가 한 손가락으로 그릴 수 있을 뿐만 아니라 한 번에 여러 손가락으로 그릴 수도 있습니다. 프로그램에서 여러 터치 이벤트를 처리할 때 각 손가락에 해당하는 이벤트를 구분해야 합니다. Android는 이 목적을 위해 ID 코드를 제공하지만 해당 코드를 가져오고 처리하는 것은 약간 까다로울 수 있습니다.

특정 손가락과 연결된 모든 이벤트의 경우 ID 코드는 동일하게 기본. ID 코드는 손가락이 화면을 처음 터치할 때 할당되고 화면에서 손가락을 떼면 유효하지 않습니다. 이러한 ID 코드는 일반적으로 매우 작은 정수이며 Android는 이후 터치 이벤트에 다시 사용합니다.

거의 항상 개별 손가락을 추적하는 프로그램은 터치 추적을 위한 사전을 기본. 사전 키는 특정 손가락을 식별하는 ID 코드입니다. 사전 값은 애플리케이션에 따라 달라집니다. Finger그림판 샘플에서 각 손가락 스트로크(터치에서 해제)는 해당 손가락으로 그린 선을 렌더링하는 데 필요한 모든 정보를 포함하는 개체와 연결됩니다. 이 프로그램은 이 목적을 위해 작은 FingerPaintPolyline 클래스를 정의합니다.

class FingerPaintPolyline
{
    public FingerPaintPolyline()
    {
        Path = new Path();
    }

    public Color Color { set; get; }

    public float StrokeWidth { set; get; }

    public Path Path { private set; get; }
}

각 폴리라인에는 색, 스트로크 너비 및 Android 그래픽 Path 개체가 그려질 때 선의 여러 점을 누적하고 렌더링할 수 있습니다.

아래에 표시된 코드의 re기본der는 명명FingerPaintCanvasView된 파생 항목에 View 포함되어 있습니다. 이 클래스는 기본 하나 이상의 손가락으로 적극적으로 그려지는 동안 형식 FingerPaintPolyline 개체의 사전을 포함합니다.

Dictionary<int, FingerPaintPolyline> inProgressPolylines = new Dictionary<int, FingerPaintPolyline>();

이 사전을 사용하면 보기에서 특정 손가락과 연결된 정보를 빠르게 가져올 FingerPaintPolyline 수 있습니다.

또한 클래스는 FingerPaintCanvasView 완료된 폴리라인에 대한 개체를 기본.List

List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();

List 개체의 개체는 그렸던 순서와 같습니다.

FingerPaintCanvasView 는 다음으로 정의된 View두 가지 메서드를 재정의합니다. OnDrawOnTouchEvent. OnDraw 재정의에서 뷰는 완성된 폴리라인을 그린 다음 진행 중인 폴리라인을 그립니다.

메서드의 재정의 OnTouchEvent 는 속성에서 값을 가져와 pointerIndex 서 시작합니다 ActionIndex . 이 ActionIndex 값은 여러 손가락을 구분하지만 여러 이벤트에서 일치하지 않습니다. 이러한 이유로 메서드에서 GetPointerId 포인터 id 값을 가져오는 데 사용합니다pointerIndex. 이 ID 는 여러 이벤트에서 일관됩니다 .

public override bool OnTouchEvent(MotionEvent args)
{
    // Get the pointer index
    int pointerIndex = args.ActionIndex;

    // Get the id to identify a finger over the course of its progress
    int id = args.GetPointerId(pointerIndex);

    // Use ActionMasked here rather than Action to reduce the number of possibilities
    switch (args.ActionMasked)
    {
        // ...
    }

    // Invalidate to update the view
    Invalidate();

    // Request continued touch input
    return true;
}

재정의는 속성이 아닌 Action 문의 속성을 switch 사용합니다ActionMasked. 이유는 다음과 같습니다.

멀티 터치 Action 를 처리할 때 속성에는 첫 번째 손가락이 MotionEventsAction.Down 화면을 터치할 수 있는 값이 있으며 두 번째 및 Pointer3Down 세 번째 손가락도 화면을 터치할 때 값 Pointer2Down 이 있습니다. 네 번째와 다섯 번째 손가락이 접촉할 때 Action 속성에는 열거형의 MotionEventsAction 멤버에 해당하지 않는 숫자 값이 있습니다. 값의 비트 플래그 값을 검사하여 의미를 해석해야 합니다.

마찬가지로 손가락이 화면 Action 과 접촉할 때 속성에는 두 번째 및 Pointer3Up 세 번째 손가락과 첫 번째 손가락 UpPointer2Up 값이 있습니다.

속성은 ActionMasked 여러 손가락을 구분하기 위해 속성과 함께 ActionIndex 사용되기 때문에 더 적은 수의 값을 사용합니다. 손가락이 화면을 터치하면 속성은 첫 번째 손가락과 PointerDown 후속 손가락에 대해서만 같 MotionEventActions.Down 을 수 있습니다. 손가락이 화면을 ActionMasked 나가면 후속 손가락과 Up 첫 번째 손가락에 Pointer1Up 대한 값이 있습니다.

사용할 ActionMaskedActionIndex 때는 화면을 터치하고 나가기 위해 후속 손가락을 구분하지만 일반적으로 개체의 다른 메서드 MotionEvent 에 대한 인수를 제외하고는 해당 값을 사용할 필요가 없습니다. 멀티 터치의 경우 위의 코드에서 이러한 메서드 중 가장 중요한 방법 중 하나가 호출됩니다 GetPointerId . 이 메서드는 사전 키에 특정 이벤트를 손가락에 연결하는 데 사용할 수 있는 값을 반환합니다.

샘플의 재정의는 OnTouchEvent 새 개체를 MotionEventActions.Down 만들고 사전에 추가하여 이벤트와 PointerDown 이벤트를 FingerPaintPolyline 동일하게 처리합니다.

public override bool OnTouchEvent(MotionEvent args)
{
    // Get the pointer index
    int pointerIndex = args.ActionIndex;

    // Get the id to identify a finger over the course of its progress
    int id = args.GetPointerId(pointerIndex);

    // Use ActionMasked here rather than Action to reduce the number of possibilities
    switch (args.ActionMasked)
    {
        case MotionEventActions.Down:
        case MotionEventActions.PointerDown:

            // Create a Polyline, set the initial point, and store it
            FingerPaintPolyline polyline = new FingerPaintPolyline
            {
                Color = StrokeColor,
                StrokeWidth = StrokeWidth
            };

            polyline.Path.MoveTo(args.GetX(pointerIndex),
                                 args.GetY(pointerIndex));

            inProgressPolylines.Add(id, polyline);
            break;
        // ...
    }
    // ...        
}

pointerIndex 보기 내에서 손가락의 위치를 가져오는 데도 사용됩니다. 모든 터치 정보는 값과 pointerIndex 연결됩니다. 여러 id 메시지에서 손가락을 고유하게 식별하므로 사전 항목을 만드는 데 사용됩니다.

마찬가지로 재정의는 OnTouchEvent 완료된 폴리라인을 컬렉션으로 전송하여 재정의 completedPolylines 중에 OnDraw 그릴 수 있도록 처리하고 Pointer1Up 동일하게 처리 MotionEventActions.Up 합니다. 또한 코드는 사전에서 항목을 제거 id 합니다.

public override bool OnTouchEvent(MotionEvent args)
{
    // ...
    switch (args.ActionMasked)
    {
        // ...
        case MotionEventActions.Up:
        case MotionEventActions.Pointer1Up:

            inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
                                                args.GetY(pointerIndex));

            // Transfer the in-progress polyline to a completed polyline
            completedPolylines.Add(inProgressPolylines[id]);
            inProgressPolylines.Remove(id);
            break;

        case MotionEventActions.Cancel:
            inProgressPolylines.Remove(id);
            break;
    }
    // ...        
}

이제 까다로운 부분에 대한.

다운 및 업 이벤트 사이에는 일반적으로 많은 MotionEventActions.Move 이벤트가 있습니다. 이러한 항목은 단일 호출로 OnTouchEvent번들로 제공되며 이벤트 및 이벤트와 Up 다르게 Down 처리되어야 합니다. 속성에서 이전에 가져온 값은 pointerIndexActionIndex 무시해야 합니다. 대신 메서드는 0과 PointerCount 속성 사이를 반복하여 여러 pointerIndex 값을 가져온 다음 각 pointerIndex 값에 대한 값을 가져와 id 야 합니다.

public override bool OnTouchEvent(MotionEvent args)
{
    // ...
    switch (args.ActionMasked)
    {
        // ...
        case MotionEventActions.Move:

            // Multiple Move events are bundled, so handle them differently
            for (pointerIndex = 0; pointerIndex < args.PointerCount; pointerIndex++)
            {
                id = args.GetPointerId(pointerIndex);

                inProgressPolylines[id].Path.LineTo(args.GetX(pointerIndex),
                                                    args.GetY(pointerIndex));
            }
            break;
        // ...
    }
    // ...        
}

이러한 유형의 처리를 통해 샘플은 개별 손가락을 추적하고 화면에 결과를 그릴 수 있습니다.

손가락의 예제 스크린샷그림판 예제

이제 화면에서 개별 손가락을 추적하고 구분하는 방법을 살펴보았습니다.