page.title=입력 이벤트 parent.title=사용자 인터페이스 parent.link=index.html @jd:body

이 문서의 내용

  1. 이벤트 수신기
  2. 이벤트 처리기
  3. 터치 모드
  4. 초점 처리하기

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

레이아웃을 작성하는 데 사용하게 되는 여러 가지 보기 클래스 안을 보면 UI 이벤트에 유용해 보이는 공개 콜백 메서드가 여러 개 있는 것이 눈에 띕니다. 이러한 메서드는 해당 객체에서 각각의 작업이 발생할 때 Android 프레임워크가 호출하는 것입니다. 예를 들어 보기(예: 버튼)를 하나 터치하면 해당 객체에서 onTouchEvent() 메서드가 호출됩니다. 그러나 이것을 가로채려면 클래스를 확장하고 메서드를 재정의해야 합니다. 다만 그런 이벤트를 처리하기 위해 모든 보기 객체를 다 확장하는 것은 타당성이 없습니다. 이 때문에 보기 클래스에 일련의 중첩된 인터페이스가 있고 거기에 훨씬 쉽게 정의할 수 있는 콜백에 있습니다. 이와 같은 인터페이스를 일명 이벤트 수신기라고 하는데, 이것이 UI와 사용자 상호 작용을 캡처하는 데 아주 적합합니다.

사용자 상호 작용을 수신 대기하는 데에는 이벤트 수신기를 사용하는 것이 좀 더 보편적이지만, 사용자 지정 구성 요소를 구축하기 위해 보기 클래스를 확장하고자 하는 상황이 올 수도 있습니다. 어쩌면 {@link android.widget.Button} 클래스를 확장하여 무언가 더 복잡한 것을 만들고자 할 수도 있습니다. 이런 경우, 클래스에 대한 기본 이벤트 행동을 클래스 이벤트 처리기를 사용하여 정의할 수 있습니다.

이벤트 수신기

이벤트 수신기란 {@link android.view.View} 클래스 내에 있는 일종의 인터페이스로, 이 안에 하나의 콜백 메서드가 들어있습니다. 이러한 메서드는 수신기가 등록된 보기가 UI 안의 항목과 사용자의 상호 작용으로 인하여 트리거되었을 때 Android 프레임워크가 호출하는 것입니다.

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

onClick()
{@link android.view.View.OnClickListener}에서 온 것입니다. 이것이 호출되는 것은 사용자가 항목을 터치하거나 (터치 모드에 있을 때), 탐색 키 또는 트랙볼을 사용하여 해당 항목에 초점을 맞추고 있으면서 적절한 "엔터" 키를 누르거나 트랙볼을 꾹 누를 때입니다.
onLongClick()
{@link android.view.View.OnLongClickListener}에서 온 것입니다. 이것이 호출되는 것은 사용자가 항목을 길게 누르거나(터치 모드에 있을 때), 탐색 키 또는 트랙볼을 사용하여 해당 항목에 초점을 맞추고 있으면서 적절한 "엔터" 키를 누르거나 트랙볼을 꾹 누를 때입니다(일 초간).
onFocusChange()
{@link android.view.View.OnFocusChangeListener}에서 온 것입니다. 이것이 호출되는 것은 사용자가 탐색 키 또는 트랙볼을 사용하여 항목 쪽으로 이동하거나 항목에서 멀어질 때입니다.
onKey()
{@link android.view.View.OnKeyListener}에서 온 것입니다. 이것이 호출되는 것은 사용자가 항목에 초점을 맞추고 있으면서 기기에 있는 하드웨어 키를 누르거나 키에서 손을 떼는 경우입니다.
onTouch()
{@link android.view.View.OnTouchListener}에서 온 것입니다. 이것이 호출되는 것은 사용자가 터치 이벤트로서의 자격을 만족하는 작업을 수행하는 경우로, 여기에 누르기, 손 떼기와 화면에서 이루어지는 모든 움직임 동작(항목의 경계 내에서)이 포함됩니다.
onCreateContextMenu()
{@link android.view.View.OnCreateContextMenuListener}에서 온 것입니다. 이것을 호출하는 것은 컨텍스트 메뉴가 구축되는 중일 때입니다(정체된 "롱 클릭"의 결과로). 메뉴 개발자 가이드에 있는 컨텍스트 메뉴 관련 논의를 참조하십시오.

이러한 메서드는 각자의 인터페이스 안에 거주하는 유일한 주민입니다. 이러한 메서드 중 하나를 정의하고 이벤트를 처리하려면 액티비티 내의 중첩된 인터페이스를 구현하거나 익명의 클래스로 정의하면 됩니다. 그런 다음 구현의 인스턴스 하나를 각각의 View.set...Listener() 메서드에 전달하십시오 (예: {@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}를 호출한 다음 이를 {@link android.view.View.OnClickListener OnClickListener}의 구현에 전달합니다).

아래의 예시는 버튼에 대하여 온-클릭 수신기를 등록하는 방법을 나타낸 것입니다.

// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(mCorkyListener);
    ...
}

OnClickListener를 액티비티의 일부로 구현하는 것이 더 편리할 수도 있습니다. 이렇게 하면 클래스 부하와 객체 할당이 추가되는 것을 피할 수 있습니다. 예:

public class ExampleActivity extends Activity implements OnClickListener {
    protected void onCreate(Bundle savedValues) {
        ...
        Button button = (Button)findViewById(R.id.corky);
        button.setOnClickListener(this);
    }

    // Implement the OnClickListener callback
    public void onClick(View v) {
      // do something when the button is clicked
    }
    ...
}

위의 예시에서 onClick() 콜백에는 반환 값이 없지만 다른 이벤트 수신기 메서드 중에는 부울 값을 반환해야만 하는 것도 있다는 점을 유의하십시오. 그 이유는 이벤트에 따라 다릅니다. 이런 필수 사항이 적용되는 몇몇 메서드의 경우, 이유는 다음과 같습니다.

하드웨어 키 이벤트는 항상 현재 초점의 중심에 있는 보기로 전달된다는 점을 명심하십시오. 이들은 보기 계층의 맨 위에서 시작하여 아래 방향으로 발송되어 적절한 목적지에 도달할 때까지 계속합니다. 보기(또는 보기의 하위)에 현재 초점이 맞춰져 있으면, 이벤트가 {@link android.view.View#dispatchKeyEvent(KeyEvent) dispatchKeyEvent()} 메서드를 통과하여 이동하는 것을 확인할 수 있습니다. 보기를 통해 키 이벤트를 캡처하는 대신, 액티비티 내부의 모든 이벤트를 {@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}을 사용하여 수신할 수도 있습니다.

또한, 애플리케이션에 대한 텍스트 입력의 경우 대다수의 기기에는 소프트웨어 입력 메서드만 있다는 사실을 명심하십시오. 그러한 메서드는 반드시 키 기반이 아니어도 됩니다. 음성 입력, 손글씨 등을 사용하는 것도 있습니다. 입력 메서드가 키보드 같은 인터페이스를 표시하더라도 일반적으로 {@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()} 이벤트군을 트리거하지는 않습니다. 특정 키 누름을 제어해야만 하는 UI는 절대 구축하면 안 됩니다. 이렇게 하면 애플리케이션이 하드웨어 키보드가 있는 기기에만 한정됩니다. 특히, 사용자가 리턴 키를 누르면 입력의 유효성을 검사하는 데 이와 같은 메서드에 의존해서는 안 됩니다. 대신, {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}과 같은 작업을 사용하여 애플리케이션이 반응할 것으로 기대되는 방식에 해당되는 입력 메서드를 신호하여 의미 있는 방식으로 UI를 변경할 수 있게 하는 것이 좋습니다. 소프트웨어 입력 메서드가 어떻게 작동할지 임의로 추정하지 마시고, 이미 서식 지정된 텍스트를 애플리케이션에 제공해줄 것이라 믿으면 됩니다.

참고: Androids는 우선 이벤트 처리기부터 호출하고, 그 다음에 클래스 정의로부터 가져온 적절한 기본 처리기를 두 번째로 호출합니다. 따라서, 이와 같은 이벤트 수신기에서 을 반환하면 이벤트가 다른 이벤트 수신기로 전파되는 것을 중지시킬 뿐만 아니라 보기에 있는 기본 이벤트 처리기로의 콜백도 차단하게 됩니다. 따라서 을 반환하는 경우 해당 이벤트를 종료하고 싶은 것인지 확신해야 합니다.

이벤트 처리기

보기에서 사용자 지정 구성 요소를 구축하는 경우, 기본 이벤트 처리기로 사용될 콜백 메서드를 여러 개 정의할 수 있게 됩니다. 사용자 지정 구성 요소에 대한 문서를 보면 이벤트 처리에 사용되는 몇 가지 보편적인 콜백을 확인할 수 있습니다. 다음은 그 몇 가지 예입니다.

개발자 여러분이 알아두어야 하는 다른 메서드가 몇 가지 더 있습니다. 이들은 보기 클래스의 일부분이 아니지만, 이벤트를 처리할 수 있는 방식에 직접적으로 영향을 미칠 수 있는 것들입니다. 그러니, 레이아웃 안에서 좀 더 복잡한 이벤트를 관리하는 경우, 이와 같은 다른 메서드도 고려하십시오.

터치 모드

사용자가 방향 키 또는 트랙볼을 사용하여 사용자 인터페이스를 탐색하고 있는 경우, 조치 가능한 항목(예: 버튼)에 초점을 맞춰 어느 것이 입력을 허용할지 사용자가 볼 수 있도록 해야 합니다. 하지만 기기에 터치 기능이 있고 사용자가 인터페이스를 터치하여 인터페이스와의 상호 작용을 시작하는 경우라면, 더 이상 항목을 강조 표시하거나 특정 보기에 초점을 맞추지 않아도 됩니다. 따라서 "터치 모드"라고 불리는 상호 작용에 대한 모드가 따로 있습니다.

터치 기능이 있는 기기의 경우, 사용자가 화면을 터치하면 기기가 터치 모드에 진입하게 됩니다. 이 시점부터는 {@link android.view.View#isFocusableInTouchMode}가 참인 보기에만 초점을 맞출 수 있습니다. 예를 들어 텍스트 편집 위젯이 이에 해당됩니다. 버튼처럼 터치할 수 있는 다른 보기의 경우 터치해도 주의를 끌 수 없으며 이를 누르면 그저 온-클릭 수신기를 실행시키기만 합니다.

사용자가 방향 키를 누르거나 트랙볼로 스크롤 동작을 할 때마다 기기가 터치 모드를 종료하고 초점을 맞출 보기를 찾습니다. 이제 사용자는 사용자 인터페이스와 상호 작용을 재개해도 되며, 화면을 터치하지 않아도 됩니다.

터치 모드 상태는 시스템 전체를 통틀어 유지됩니다(모든 창과 액티비티 포함). 현재 상태를 쿼리하려면 {@link android.view.View#isInTouchMode}를 호출하여 기기가 현재 터치 모드에 있는지 확인하면 됩니다.

초점 처리하기

프레임워크가 사용자 입력에 응답하여 일상적인 초점 이동을 처리합니다. 여기에는 보기가 제거되거나 숨겨지는 것, 또는 새 보기를 사용할 수 있게 됨에 따라 초점을 변경하는 것이 포함됩니다. 보기는 초점을 취하고자 하는 의향을 {@link android.view.View#isFocusable()} 메서드를 통해 나타냅니다. 보기가 초점을 취할 수 있는지 여부를 변경하려면 {@link android.view.View#setFocusable(boolean) setFocusable()}을 호출합니다. 터치 모드에 있는 경우, 어느 보기가 {@link android.view.View#isFocusableInTouchMode()}로 초점을 취하는 것을 허용하는지 여부를 쿼리할 수 있습니다. 이것은 {@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}로 변경하면 됩니다.

초점 이동은 주어진 방향에서 가장 가까운 이웃을 찾아내는 알고리즘을 기반으로 합니다. 드문 일이지만 기본 알고리즘이 개발자가 의도한 행동과 일치하지 않는 경우도 있습니다. 이러한 상황이라면, 레이아웃 파일에서 다음과 같은 XML 속성을 사용하여 명시적 재정의를 제공하면 됩니다. nextFocusDown, nextFocusLeft, nextFocusRight, 및 nextFocusUp입니다. 이와 같은 속성 중 한 가지를 초점이 떠나고 있는 보기에 추가합니다. 속성의 값을 초점을 맞춰야 할 보기의 ID가 되도록 정의합니다. 예:

<LinearLayout
    android:orientation="vertical"
    ... >
  <Button android:id="@+id/top"
          android:nextFocusUp="@+id/bottom"
          ... />
  <Button android:id="@+id/bottom"
          android:nextFocusDown="@+id/top"
          ... />
</LinearLayout>

보통은 이런 수직 레이아웃에서 첫 버튼부터 위로 이동하면 아무 데도 갈 수 없고, 두 번째 버튼에서 아래로 이동해도 마찬가지입니다. 이제 맨 위 버튼이 맨 아래 버튼을 다음과 같이 정의했습니다. nextFocusUp (반대쪽도 마찬가지) 따라서 이동 초점은 위에서 아래로 갔다가 아래에서 위로 순환하게 됩니다.

보기를 UI에서 초점을 맞출 수 있는 것으로 선언하고자 하는 경우(일반적으로는 그렇지 않음), 보기에 레이아웃 선언에서 android:focusable XML 속성을 추가합니다. 이 값을 으로 설정합니다. 터치 모드에 있을 때에도 보기를 초점을 맞출 수 있는 것으로 선언할 수 있습니다. android:focusableInTouchMode를 사용하면 됩니다.

특정 보기에 초점을 맞추기를 요청하려면, {@link android.view.View#requestFocus()}를 호출하십시오.

초점 이벤트를 수신 대기하려면(어떤 보기에 초점이 맞춰지거나 이를 잃는 경우 알림을 받으려면), {@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}를 사용하면 됩니다. 이는 위의 이벤트 수신기 섹션에서 이야기한 바와 같습니다.