page.title=入力イベント parent.title=ユーザー インターフェース parent.link=index.html @jd:body

本書の内容

  1. イベントリスナ
  2. イベント ハンドラ
  3. タッチモード
  4. フォーカスの処理

Android では、アプリケーションでのユーザーの操作からイベントをインターセプトする方法が複数用意されていますが、ユーザー インターフェース内のイベントをインターセプトする場合は、ユーザーが操作する個々の View オブジェクトからイベントを取得することになります。 View クラスは、このための手段を提供しています。

レイアウトを構成するために使用する各種の View クラスには、UI イベントの処理に役に立ついくつかのパブリック コールバック メソッドが含まれています。 これらのパブリック コールバック メソッドは、オブジェクトで対応するアクションが発生したときに Android フレームワークによって呼び出されます。 たとえば、ビュー(ボタンなど)がタップされたときには、そのオブジェクト上で onTouchEvent() メソッドが呼び出されます。 このようなイベントをインターセプトするには、クラスを継承しメソッドをオーバーライドする必要があります。 ただし、このようなイベントを処理するたびに View オブジェクトを継承することは、実用的とは言えません。 そのため、View クラスには、簡単に定義できるコールバックを持つネストされたインターフェースのコレクションも含まれています。 これらのインターフェースは、イベントリスナと呼ばれ、UI へのユーザーの操作を取得するために使用されます。

通常は、イベントリスナを使用して、ユーザーの操作をリッスンすることになりますが、カスタム コンポーネントを作成するために View クラスを継承する場合や、 処理を工夫するために {@link android.widget.Button} クラスを継承することもできます。 その場合は、クラスのイベント ハンドラを使用して、クラスにデフォルトのイベント動作を定義できます。

イベントリスナ

イベントリスナは、コールバック メソッド 1 つを含む {@link android.view.View} クラスのインターフェースです。 以下のメソッドは、イベントリスナが登録されているビューが UI アイテムへのユーザーの操作によってトリガーされたときに、Android フレームワークによって呼び出されます。

イベントリスナ インターフェースに含まれているのは、以下のコールバック メソッドです。

onClick()
{@link android.view.View.OnClickListener} のメソッド。ユーザーがアイテムをタップしたとき(タッチモードの場合)、またはナビゲーション キーまたはトラックボールでアイテムにフォーカスを合わせ、適切な「エンター」キーまたはトラックボールを押したときに、呼び出されます。
onLongClick()
{@link android.view.View.OnLongClickListener} のメソッド。ユーザーがアイテムをタップしてホールドしたとき(タッチモードの場合)、またはナビゲーション キーまたはトラックボールでアイテムにフォーカスを合わせ、適切な「エンター」キーまたはトラックボールを長押し(1 秒間)したときに、呼び出されます。
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} の実装を渡します)。

次の例は、ボタンへの on-click リスナの登録方法を示しています。

// 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 を意味のあるものにします。 ソフトウェア入力メソッドの動作を推測し、その推測に基づいて、書式設定済みのテキストをアプリケーションに提供することは避けてください。

注: Android では、まずイベント ハンドラが呼び出され、次にクラス定義から適切なデフォルト ハンドラが呼び出されます。 そのため、これらのイベントリスナから true が返された場合、イベントの他のイベントリスナへの伝播は止まり、ビューのデフォルトのイベント ハンドラへのコールバックもブロックされます。 そのため、イベントを終了させたいことが確実な場合のみ、true を返すようにしてください。

イベント ハンドラ

ビューからカスタム コンポーネントを作成する場合、デフォルトのイベント ハンドラとして使用される複数のコールバック メソッドを定義できます。イベント ハンドリングに使用される次のような一般的なコールバックの一部については、詳細をカスタム コンポーネントについてのドキュメントでご覧いただけます。

View クラスに含まれていないメソッドの中にも、イベントの処理の方法に直接関係するメソッドがいくつかあります。 そのため、レイアウト内の複雑なイベントを管理する場合は、以下のメソッドの使用を検討してください。

タッチモード

ユーザーが方向キーまたはトラックボールを使用してユーザー インターフェースを操作する場合、入力を受け付けるアイテムがどのアイテムなのかユーザーが知ることができるようにアクション可能なアイテム(ボタンなど)にフォーカスを与えることが必要になります。 ただし、端末にタッチ機能がある場合は、ユーザーはタップでインターフェースの操作を開始するため、アイテムをハイライトすることや、特定のビューにフォーカスを与えることは必要ではなくなりました。 そのため、「タッチモード」と名付けられた操作モードが存在します。

タッチ可能な端末では、ユーザーが画面をタップすると、端末がタッチモードになります。 端末がタッチモードの場合、テキスト編集ウィジェットなどの {@link android.view.View#isFocusableInTouchMode} が true のビューのみがフォーカス可能であり、ボタンなどのタップ可能なその他のビューは、タップされたときにフォーカスされることはありません。それらのビューは、押されたときに、on-click リスナを起動します。

ユーザーが方向キーを押すか、またはトラックボールをスクロールすると、端末はタッチモードから抜け、ビューがフォーカスを取得します。 これにより、ユーザーは、画面をタップすることなく、ユーザー インターフェースの操作を再開できます。

タッチモード状態は、システム全体(すべてのウィンドウとアクティビティ)で維持されます。端末が現在タッチモードかどうか確認するには、{@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()} で変更できます。

フォーカスの移動は、所定の方向で最も近くにあるアイテムを見つけるアルゴリズムに基づきますが、 まれに、デフォルトのアルゴリズムが開発者の意図する動作と一致しない場合もあります。 この場合、レイアウト ファイルの nextFocusDownnextFocusLeftnextFocusRightnextFocusUp の各 XML 属性を明示的にオーバーライドできます。これらの属性のいずれかを、フォーカスの移動のビューに追加します。 フォーカスの移動のビューの ID になる属性の値を定義します。 次に例を示します。

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

本来、上記の縦方向のレイアウトでは、1 番上のボタンから上に移動しようとしても、2 番目のボタンから下に移動しようしても、どこにもフォーカスが移動しないはずでしたが、上記の処理により、 1 番上のボタンによって 1 番下のボタンが nextFocusUp として定義され(逆の場合も同様)、フォーカスが、上から下と下から上に順番に移動するようになります。

UI でビューをフォーカス可能にする場合は(従来は、ビューはフォーカス可能ではありません)、レイアウトの宣言で android:focusable XML 属性をビューに追加し、値を true に設定します。また、android:focusableInTouchMode を使用して、タッチモードのときにビューをフォーカス可能にすることもできます。

特定のビューへのフォーカスをリクエストするには、{@link android.view.View#requestFocus()} を呼び出します。

フォーカス イベントをリッスンするには(ビューがフォーカスを受け取ったときまたは失ったときに通知を受け取るには)、上記のイベントリスナのセクションの説明に従って {@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()} を使用します。