[android]04. 이벤트

목차

  1. 입력 이벤트 개요
  2. 이벤트 리스너
  3. TouchEvent
  4. GestureDetector
  5. Simple Gesture
  6. key event



입력 이벤트 개요

Android에는 사용자와 애플리케이션의 상호작용으로부터 이벤트를 가로채는 방법이 여러 가지 있습니다. 사용자 인터페이스 내의 이벤트일 경우, 해당 이벤트를 사용자가 상호작용하는 특정 View 객체로부터 캡처하는 방법을 사용합니다. 이에 필요한 수단은 View 클래스가 제공합니다.

예를 들어, View(예: 버튼)를 하나 터치하면 해당 객체에서 onTouchEvent() 메서드가 호출됩니다. 그러나 이것을 가로채려면 클래스를 확장하고 메서드를 재정의해야 합니다. 다만 그런 이벤트를 처리하기 위해 모든 View 객체를 확장하는 것은 타당성이 없습니다. 이 때문에 View 클래스에도 일련의 중첩된 인터페이스가 있고 거기에 훨씬 쉽게 정의할 수 있는 콜백이 있습니다. 이와 같은 인터페이스를 이벤트 리스너라고 하며, UI와의 사용자 상호작용을 캡처하는 데 적합합니다.

이벤트 리스너

이벤트 리스너란 View 클래스 내에 있는 일종의 인터페이스로, 이 안에 하나의 콜백 메서드가 들어 있습니다. 이러한 메서드는 리스너가 등록된 뷰가 UI 안의 항목과 사용자의 상호작용으로 인해 트리거되었을 때 Android 프레임워크가 호출합니다.

이벤트 리스너 인터페이스에 포함된 콜백 메서드는 다음과 같습니다.

  • onClick()
    View.OnClickListener에서 온 것입니다. 이 메서드는 사용자가 항목을 터치하거나, 탐색 키 또는 트랙볼을 사용하여 해당 항목에 포커스를 맞추고 적절한 ‘Enter’ 키를 누르거나, 트랙볼을 누르면 호출됩니다.

    1: 마우스와 같은 컴퓨터를 제어하는데 사용되는 포인팅 장치의 종류 중 하나

  • onLongClick()
    View.OnLongClickListener에서 온 것입니다. 이 메서드는 사용자가 (터치 모드에 있을 때) 항목을 길게 누르거나, 탐색 키 또는 트랙볼을 사용하여 해당 항목에 포커스를 맞추고 적절한 ‘Enter’ 키를 누르거나, 트랙볼을 누르면 호출됩니다(1초간).
  • onFocusChange()
    View.OnFocusChangeListener에서 온 것입니다. 이 메서드는 사용자가 탐색 키 또는 트랙볼을 사용하여 항목 쪽으로 이동하거나 항목에서 멀어지면 호출됩니다.
  • onKey()
    View.OnKeyListener에서 온 것입니다. 이 메서드는 사용자가 항목에 포커스를 맞추고 있으면서 기기에 있는 하드웨어 키를 누르거나 키에서 손을 떼면 호출됩니다.
  • onTouch()
    View.OnTouchListener에서 온 것입니다. 이 메서드는 사용자가 터치 이벤트 작업을 수행하는 경우에 호출되며, 여기에는 누르기, 손 떼기와 화면에서 이루어지는 모든 동작이 포함됩니다.
  • onCreateContextMenu()
    View.OnCreateContextMenuListener에서 온 것입니다. 이 메서드는 컨텍스트 메뉴가 구축되는 중일 때 호출됩니다(정체된 “길게 클릭”의 결과로). 메뉴 개발자 가이드에 있는 컨텍스트 메뉴 관련 논의를 참조하세요.

공식 문서 - 이벤트 리스너



TouchEvent

onTouchEvent()의 대안으로 setOnTouchListener() 메서드를 사용하여 View.OnTouchListener 객체를 View 객체에 연결할 수 있습니다. 이렇게 하면 기존 View의 서브클래스를 생성하지 않고 터치 이벤트를 수신할 수 있습니다.

java 코드
public class MainActivity extends AppCompatActivity {
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        View view = findViewById(R.id.view);
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                int action = motionEvent.getAction();
                float x = motionEvent.getX();
                float y = motionEvent.getY();
                if (action == MotionEvent.ACTION_DOWN) {
                    println("손가락 눌림: "+x+", "+y);
                } else if (action == MotionEvent.ACTION_MOVE) {
                    println("손가락 움직임: "+x+", "+y);
                } else if (action == MotionEvent.ACTION_UP) {
                    println("손가락 뗌: "+x+", "+y);
                }
                return true;
            }
        });
    }
    public void println(String data) {
        textView.append(data+"\n");
    }
}
xml 코드
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <View
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@color/colorAccent" />

    <View
        android:id="@+id/view2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@color/colorPrimary" />
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#000000"
            android:textSize="16dp" />
    </ScrollView>


</LinearLayout>

첫 번째 칸을 클릭하면 evnet 정보가 세 번째 칸에 출력된다.

0401



GestureDetector

Android는 일반적인 동작을 감지하기 위한 GestureDetector 클래스를 제공합니다. 이 클래스는 onDown(), onLongPress(), onFling() 등의 동작을 지원합니다. 위에서 설명한 onTouchEvent() 메서드와 함께 GestureDetector를 사용할 수 있습니다.

GestureDetector.OnGestureListener는 특정 터치 이벤트가 발생하면 사용자에게 알립니다. GestureDetector 객체가 이벤트를 수신할 수 있게 하려면 뷰 또는 활동의 onTouchEvent() 메서드를 재정의하고 관찰된 모든 이벤트를 감지기 인스턴스에 전달합니다.

메소드 이벤트 유형
onDown() 화면에 눌렸을 경우
onShowPress() 화면이 눌렸다 떼어지는 경우
onSingleTapUp() 화면이 한 손가락으로 눌렸다 떼어지는 경우
onSingleTapConfirmed() 화면이 한 손가락으로 눌러지는 경우
onDoubleTap() 화면이 두 손가락으로 눌러지는 경우
onDoubleTapEvent() 화면에 두 손가락으로 눌려진 상태에서 떼거나 이동하는 등 세부적인 액션을 취하는 경우
onScroll() 화면이 눌린 채 일정한 속도와 방향으로 움직였다 떼는 경우
onFling() 화면이 눌린 채 가속도를 붙여 움직였다 떼는 경우
onLongPress() 화면을 손가락으로 오래 누르는 경우

공식 문서 - 동작 감지


GestureDetector 예시

위의 TouchEvent 예시와 이어진다.

java 코드
        GestureDetector detector;
        detector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
        @Override
         public boolean onDown(MotionEvent motionEvent) {
             println("onDown() 호출됨");
            return false;
        }
        @Override
        public void onShowPress(MotionEvent motionEvent) {
            println("onShowPress() 호출됨");
        }
        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            println("onSingleTapUp() 호출됨");
           return false;
        }

        @Override
        public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
            println("onScroll() 호출됨: "+v+", "+v1);
            return false;
        }

        @Override
        public void onLongPress(MotionEvent motionEvent) {
            println("onLongPress() 호출됨");
        }

        @Override
        public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
            println("onFling() 호출됨"+v+", "+v1);
            return false;
        }
    });
    View view2 = findViewById(R.id.view2);
    view2.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            detector.onTouchEvent(motionEvent);
            return true;
        }
    });

0402



Simple Gesture

몇 가지 동작만 처리하려면 GestureDetector.OnGestureListener 인터페이스를 구현하는 대신 GestureDetector.SimpleOnGestureListener를 확장하면됩니다. GestureDetector.SimpleOnGestureListener는 모든 onTouchEvent 메서드에 관해 false를 반환하여 메서드의 구현을 제공합니다. 따라서 필요한 메서드만 재정의할 수 있습니다.

GestureDetector.OnGestureListener의 사용 여부와 관계없이 true를 반환하는 onDown() 메서드를 구현하는 것이 좋습니다. 모든 동작이 onDown() 메시지로 시작하기 때문입니다.


Simple Gesture 예시

java 코드
public class MainActivity extends Activity {

        private GestureDetectorCompat mDetector;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mDetector = new GestureDetectorCompat(this, new MyGestureListener());
        }

        @Override
        public boolean onTouchEvent(MotionEvent event){
            this.mDetector.onTouchEvent(event);
            return super.onTouchEvent(event);
        }

        class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
            private static final String DEBUG_TAG = "Gestures";

            @Override
            public boolean onDown(MotionEvent event) {
                Log.d(DEBUG_TAG,"onDown: " + event.toString());
                return true;
            }

            @Override
            public boolean onFling(MotionEvent event1, MotionEvent event2,
                    float velocityX, float velocityY) {
                Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
                return true;
            }
        }
    }



key event

앱에서 키보드 입력을 가로채거나 직접 처리하게 만들려면 KeyEvent.Callback 인터페이스에서 onKeyDown()과 onKeyMultiple() 같은 콜백 메서드를 구현하면 됩니다.

키 코드 설명
KEYCODE_DPAD_LEFT/RIGHT/UP/DOWN/CENTER 왼쪽/오른쪽/위쪽/아래쪽/중앙 화살표
KEYCODE_CALL/ENDCALL 통화/통화 종료 버튼
KEYCODE_HOME 홈 버튼
KEYCODE_BACK 뒤로 가기 버튼
KEYCODE_VOLUME_UP/DOWN 소리 크기 증가/감소 버튼
KEYCODE_0 ~ KEYCODE_9 숫자 0부터 9까지의 키값
KEYCODE_A ~ KEYCODE_Z 알파벳 A부터 Z까지의 키값

KeyEvent 클래스 및 관련 API를 사용하여 키보드 이벤트를 처리할 때 키보드 이벤트가 하드웨어 키보드에서만 발생한다고 예상해야 합니다. 소프트 입력 방법(터치 키보드)에서 발생하는 키 이벤트를 수신한다고 생각해서는 안 됩니다.



key event 예시

gesture 예제와 이어진다.

java 코드
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK) {
            Toast.makeText(this, "시스템 [BACK] 버튼이 눌렸습니다.", Toast.LENGTH_LONG).show();
            return true;
        }
        return false;
    }