たかがフォーカス,されどフォーカス


フォーカスとタッチモード

Androidのフォーカスの制御は、タッチモードがからんでいてわかりずらい。

タッチモードについては、「faviconl. タッチモード - ソフトウェア技術ドキュメントを勝手に翻訳」を参照。

非タッチモード時とタッチモード時で、異なるAPIが存在する。

 

Activity画面にTextViewと3つのEditViewとButtonを配置する、以下のようなレイアウトファイルを作成する。

リスト1(main.xml)

このプログラムを実行して、各ウィジェットをタッチ(クリック)した場合のフォーカスの移動を確認してみる。

TextViewをタッチしてもフォーカスは、TextViewに移動しない。

EditTextの場合は、タッチする事でフォーカスを移動する事ができる。

Buttonの場合にはタッチした瞬間、一時的にフォーカスが移動するが、その後、タッチ前のフォーカスの位置に戻ってしまう。

タッチではなく、トラックボール(DPad)をUP,DOWNすると、EditTextとButtonにはフォーカスが移動するが、TextViewには移動しない事が確認できる。

このタッチモードと非タッチモードでの動作の違いは、3種類のウィジェットのfocusable属性とfocusableInTouchMode属性のデフォルト値の違いによる。

ウィジェットのfocusable属性とfocusableInTouchMode属性の値は、 View#isFocusableとView#isFocusableInTouchModeメソッドにて確認する事ができる。

次のプログラムを用いて、TextViewとEditTextとButtonのデフォルトのfocusable属性とfocusableInTouchMode属性を確認してみる。

リスト2(FocusSample1Activity.java)

このプログラムを実行してボタンを押下すると、以下の図のようにLogCatビューに、各ウィジェットのfocusable属性とfocusableInTouchMode属性の値が出力される。

 

 

focusable属性がtrueのウィジェットは、非タッチモード時にフォーカスを取得可能なのに対して、 focusableInTouchMode属性がtrueの場合はタッチモード時にフォーカスを取得可能となる。

つまり、TextViewの場合には、focusable属性とfocusableInTouchMode属性ともにfalseのため、 非タッチモード時,タッチモード時ともにフォーカスを受け取る事ができない。

EditTextの場合は、focusable属性とfocusableInTouchMode属性ともにtrueのため、どちらのモードでもフォーカスを受け取る事ができる。

Buttonの場合には、focusable属性はtrueであるため非タッチモードではフォーカスを受け取る事ができるが、 focusableInTouchMode属性がfalseのため、タッチモードになった瞬間フォーカスを失ってしまう事になる。

 

次に、リスト1のレイアウトファイルを以下のように変更して、 TextViewとButtonも、非タッチモード,タッチモード時にフォーカスを受け取れるように、 また、2番目のEditText(editText1)のみ非タッチモードでフォーカスを受け取れないように 修正する。

  • TextViewのfocusable属性とfocusableInTouchMode属性ともにtrueに設定
  • 2番目のEditTextのみfocusable属性をfalseに設定
  • ButtonのfocusableInTouchMode属性をtrueに設定

リスト3-レイアウトファイルのfocusable属性とfocusableInTouchMode属性を修正(main.xml)

 

このレイアウトファイルを使ってリスト2のコードを実行して、focusable属性とfocusableInTouchModeの値を確認してみると、以下のようになる。

 

 

ここで、面白いのは、editText2のfocusable属性だけをfalseに設定したのに、 focusableInTouchMode属性もfalseに設定されてしまっている。

それ以外は設定どおりの値に変更されている。

ちなみにxmlではなく、コードでfocusable属性とfocusableInTouchMode属性を変更するには、 View#setFocusableとView#setFocusableInTouchModeメソッドを使う。

 

実際の動作を確認してみる。

TextViewのfocusable属性とfocusableInTouchMode属性をtrueに設定されているにもかかわらず、 TextViewにフォーカスを移しても表示はかわらない。

これは、TextViewは文字列を表示するだけのウィジェットなので、フォーカスを受け取る意味が無いからと思われる。

2番目のEditText(editText2)はfocusable属性,focusableInTouchMode属性ともにfalseになったので、 カーソルを移動してもフォーカスを受け取る事ができず、非タッチモードの場合には次のウィジェットにフォーカスが移動する。

Buttonの場合は、focusableInTouchMode属性をtrueに設定したので、タッチ時にもフォーカスを受け取る事ができるようになった。

 

以上のように、focusable属性とfocusableInTouchMode属性を変更することで、 ウィジェットのデフォルトのフォーカス可能状態を変更できるが、 これを変更するのは好ましい動作と言えないので、通常は変更しない方が良いだろう。

フォーカスの設定

View#requestFocusメソッドを使うと、指定のウィジェットにフォーカスを移動させる事ができる。

しかし、タッチモードの時には、 focusableInTouchMode属性がfalseのウィジェットにフォーカスを移動させることができないので、 このメソッドではフォーカスを移動させる事はできない。

View#requestFocusFromTouchメソッドを使うと、 タッチモード時でもfocusableInTouchMode属性がfalseのウィジェットに対して、 フォーカスを移動させることができる。

 

この、requestFocusメソッドとrequestFocusFromTouchメソッドとfocusableInTouchMode属性の関係 を確認するためのコードを以下に示す。

リスト4(FocusSample2Activity.java)

このコードは、EditTextウィジェットに対して「A」キーが押された時と、 EditTextがタッチされた時に、強引にフォーカスをButtonに移動させる事を意図したプログラムである。

しかし、同じrequestFocusメソッドを実行しているにもかかわらず、 「A」キーが押された時にはフォーカスが移動するが、タッチされた時にはフォーカスが移動しない。

これは、EditTextがタッチされた時にタッチモードに移行してしまうためである。

この問題を回避するには、ButtonのfocusableInTouchMode属性をtrueに設定してしまう事である。

そうすれば、タッチモード時でもButtonはフォーカスを受け取れるようになる。

しかし、ButtonのfocusableInTouchMode属性をtrueにしたくない場合には、 もう一つの解決方法として、39行目のrequestFocusメソッドの換わりにrequestFocusFromTouchメソッドを使う。

 

requestFocusメソッドには requestFocus(int direction)requestFocus(int, android.graphics.Rect) というオーバーロードされたメソッドもある。

イベント

フォーカスが変更された時のイベントを捕捉するには、OnFocusChangeListenerを使う。

以下のプログラムはその例です。

リスト5(FocusSample4Activity.java)

このプログラムを実行して、ウィジェットのフォーカスを変更すると、LogCatビューは下記のように表示される。

 

 

フィーカスに関するその他のトピック

xmlでフォーカスを設定

xmlレイアウトファイルにrequestFocusタグを指定する事で、フォーカスを設定する事もできる。

Androidアプリで、起動後最初にカーソルを当てるViewを指定する方法 | mucchinのAndroid戦記」 , 「favicon7.5.4 レイアウトリソース - ソフトウェア技術ドキュメントを勝手に翻訳」 を参照。

フォーカスを受け取る順番の制御

フォーカス移動の順番を変更したい場合は、nextFocusUp属性,nextFocusDown属性,android:nextFocusLeft属性,nextFocusRight属性を使う。

フォーカスを制御する - Androidプログラマへの道 ~ Moonlight 明日香 ~ - livedoor Wiki(ウィキ)」 を参照。

favicon6.5 UIイベントハンドリング - ソフトウェア技術ドキュメントを勝手に翻訳」も参照。

Enterキーによるフォーカスの移動

EditTextにsingleLine属性を指定すると、そのEditTextはエンターキーでフォーカスを移動するようになる。

リスト6(main.xml)

その他

faviconViewのフォーカスとトラバース - Kazzzの日記」や 「ソフトキーボードの制御 | GE Android Blog」 も参考になりそう。

 

ページのトップへ戻る