반응형

 

안드로이드에서 터치 기능에 대해 구현할 때 onTouchEvent() 함수를 Override하여 사용하게 된다.

 

일반적으로 동시 터치가 아닌 한 포인트의 터치만 구현할 경우 아래와 같이 사용을 한다.

 

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch(event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                    global_x = (int) (event.getX());
                    global_y = (int) (event.getY());
                    break;

            case MotionEvent.ACTION_MOVE:
                    global_x = (int) (event.getX());
                    global_y = (int) (event.getY());
                    break;
        }

        return true;
    }

 

 

간단히 설명을 하면 발생한 이벤트를 마스킹하여 현재 어떤 모션 이벤트(ACTION_DOWN? ACTION_MOVE)가 발생했는지 확인하여 그에 적절한 처리를 하게 된다.

 

위의 코드는 한 포인트에 대해서만 처리될 뿐 두 개 이상의 포인트에 대해서는 고려되있지 않다.

 

아래 코드는 두 개의 포인트에 대해 터치를 구현한 코드이다.

 

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int pointer_count = event.getPointerCount(); //현재 터치 발생한 포인트 수를 얻는다.
        if(pointer_count > 2) pointer_count = 2; //3개 이상의 포인트를 터치했더라도 2개까지만 처리를 한다.

        switch(event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: //한 개 포인트에 대한 DOWN을 얻을 때.
                    global_num[0] = event.getPointerId(0); //터치한 순간부터 부여되는 포인트 고유번호.
                    global_x[0] = (int) (event.getX());
                    global_y[0] = (int) (event.getY());
                }
                break;

            case MotionEvent.ACTION_POINTER_DOWN: //두 개 이상의 포인트에 대한 DOWN을 얻을 때.
                for(int i = 0; i < pointer_count; i++) {
                    global_num[i] = event.getPointerId(i); //터치한 순간부터 부여되는 포인트 고유번호.
                    global_x[i] = (int) (event.getX(i));
                    global_y[i] = (int) (event.getY(i));
                }
                break;

            case MotionEvent.ACTION_MOVE:
                for(int i = 0; i < pointer_count; i++) {
                    global_num[i] = event.getPointerId(i);
                    global_x[i] = (int) (event.getX(i));
                    global_y[i] = (int) (event.getY(i));
                }
                break;
        }

        return true;
    }

 

코드가 크게 길어지지도 않았고, 그리 어렵지도 않다.

 

3번째 코드에서 event.getPointerCount() 함수로 현재 터치된 포인트 수를 가져온다.

 

두 개의 손가락으로 터치하였다면 2를 반환할 것이며, 그 이상의 터치를 발생시켰을 경우 그에 대한 값을 반환할 것이다.

 

위의 코드에서는 두 개의 포인트에 대해서만 처리할 것이므로 4번째 줄에서 3개 이상의 포인트가 인식되었더라도 강제로 2개의 포인트만 처리하도록 하였다.

 

7번째줄과 15번째 줄을 보면 ACTION_DOWN, ACTION_POINTER_DOWN 이렇게 두개로 나눠져있다.

 

주석에도 설명되어있지만 ACTION_DOWN은 한 개에 대한 포인트에 대해 DOWN 이벤트가 발생했을 경우이고,

 

ACTION_POINTER_DOWN은 두 개 이상에 대한 포인트에 대해 DOWN 이벤트가 발생했을 경우이다.

 

이게 무슨 의미냐면, 두 개 이상의 터치가 발생했을 때는 ACTION_DOWN 이벤트는 발생하지 않는다.

 

반대로 한 개의 터치가 발생했을 때는 ACTION_POINTER_DOWN 이벤트가 발생하지 않는다.

 

즉, 구현하려는 어플이 두 개 이상의 포인트를 동시에 터치할 경우도 있고, 한 개의 포인트만을 터치할 경우도 있다면

 

위와 같이 두 개의 이벤트를 모두 구현해주어야 하는 것이다.

 

왜 이렇게 비효율적으로 구현했는지가 의문이지만 어쨌든 이렇게 구현을 해주어야 한다.

 

다행히도 ACTION_MOVE 이벤트의 경우는 한 개만 터치할 경우나 두 개 이상을 터치할 경우나 모두 같은 이벤트로 들어오게 되므로 별도로 나눠서 구현할 필요가 없다.

 

다음으로 8번째 줄을 보면 ACTION_DOWN의 경우는 당연히 한 포인트를 터치했을 때만 발생하므로 0번 배열에 해당 좌표 데이타를 보관하게 된다.

 

15번째 줄을 보면 발생한 포인터 수만큼 for문을 돌려 배열에 해당 좌표들을 저장하게 된다.

 

여기서 중요한 것이 16번째 줄을 보면 event.getPointerId(i)로 현재 발생한 포인터에 대한 고유 번호를 따로 저장해주고 있다.

 

이것이 왜 필요하냐면, 만약 2개 포인트를 터치하고 있다고 가정해보자.

 

global_num[0] = 0

global_x[0] = 50

global_y[0] = 50

 

global_num[1] = 1

global_x[1] = 180

global_y[1] = 180

 

위 상태에서 처음 터치한 손가락을 떼면 어떻게 될까?

 

global_num[0] = 1

global_x[0] = 180

global_y[0] = 180

 

global_num[1] = 0

global_x[1] = 0

global_y[1] = 0

 

1번 배열에 있던(두번째로 터치한 포인트) 좌표 데이타가 0번 배열로 넘어갔다.

 

당연히 손가락 하나를 뗐으므로 한 포인트만 터치되고 있는 상태로 바뀌었을 것이므로,

 

1번 배열의 데이타는 사라지고 현재 터치되고 있는 좌표 데이타가 0번 배열의 데이타로 넘어가게 된 것이다.

 

하지만 배열의 순서가 바뀌었더라도 터치 상황을 문제없이 인지할 수 있는 방법은 바로 고유 번호의 확인이다.

 

배열의 순서는 바뀌었지만, 고유 번호는 그대로 1을 유지한 채로 넘어가있다.

 

따라서, 다중 터치를 구현할 때 배열의 인덱스를 이용해서 처리하지 않고 고유 포인터 아이디 값을 확인하여 처리해야 문제되지 않는다.

 

위의 내용을 이해한다면 터치 포인트가 3개 이상인 것도 얼마든지 구현이 가능하다.

 

주의할 점을 다시 정리해보면 아래 두가지 정도인 듯 하다.

 

1. ACTION_DOWN은 터치 포인트가 1개일 때만 발생하고 ACTION_POINTER_DOWN은 터치 포인트가 2개 이상일 때만 발생하므로, 필요에 따라 두 가지를 모두 구현해주어야 한다.

 

2. 다중 터치 도중 하나 이상의 터치 포인트가 해제될 경우 좌표 변수 안에 입력되있는 좌표 데이타의 배열 순서가 뒤바뀔 수 있으므로 터치 포인터의 고유 번호를 비교하는 방식으로 구현한다.

 

반응형

+ Recent posts