Viewのフォーカスとトラバース
フォーカス制御はGUI制御の重要な処理の一つだが、Androidのようなスマートフォンでもそれは同じ。
任意のGUIにフォーカスを設定するのはJFC/SwingもAndroidも変わらない。
- GUIにフォーカスを設定する
//JFC/Swing jTextArea1.requestFocus(); //Android view.requestFocus();
逆に、フォーカスのあるGUIの参照を取得する場合、JFC/Swingならば
KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Component current = focusManager.getFocusOwner();
などとなる。
Android SDKの場合、Activityのコンテキストであればメソッド一発で取得できる。
View current = this.getCurrentFocus();
ならば、対象のGUIを基点としてその後のフォーカス遷移をトラバース(走査)する場合には、どうすれば良いだろう。
JFC/Swingの場合はFocusTraversalPolicyというクラスが(JSDK1.4以降)あるので、それを使う。
- フォーカスを得るGUIを列挙する (JFC/Swing)
//JFrameのコンテキスト中であることが前提 FocusTraversalPolicy policy = this.getFocusTraversalPolicy(); Component root = policy.getComponentAfter(this, this); ArrayListfacusables = new ArrayList (); for( Component curr = policy.getComponentAfter(this, root) ; curr != null && curr != root ; curr = policy.getComponentAfter(this, curr)) { facusables.add(curr); } //facusablesには全てのフォーカス可能なGUIの参照が格納されているはず
一方、AndroidはFocusTraversalPolicyに相当するクラスは無いが、Viewクラス及びViewGroupクラスに最初からフォーカスのトラバースの仕組みが実装されている。
View root = this.getWindow().getDecorView(); ArrayListfacusables = root.getFocusables(View.FOCUS_FORWARD); //facusablesには全てのフォーカス可能なGUIの参照が格納されているはず
例ではトップレベルのビューを基点にしているが、対象のレイアウトが決まっているのであれば、直に指定することも可能だ。
TableLayout container = (TableLayout)this.findViewById(R.id.TableLayout01); ArrayListfacusables = container.getFocusables(View.FOCUS_FORWARD);
なお、この方法で列挙の対象となるためには、それぞれのViewが以下のプロパティのいずれも真に設定されている必要がある。
isFocusable isFocusableInTouchMode
Viewのうち、ボタン類のデフォルトではこれらのプロパティの値は
isFocusable = true isFocusableInTouchMode = false
に設定されており、対象にはならないことに注意が必要だ。※
タッチモード時フォーカスの受取可能に関係なく、isFocusableがtrueのView全てを収集したい場合は、本意ではないが、以下のイディオムを利用できる。
View root = this.getWindow().getDecorView(); ArrayListfacusables = new ArrayList (); root.addFocusables(facusables, View.FOCUS_FORWARD, View.FOCUSABLES_ALL);
本意ではない、と書いたのは、そもそもaddFocusablesメソッドの本来の使用目的は親->子のビューに対してFocusbleの収集を伝搬していくことであり、一覧を収集することではないと思われる。
仮にそのような用途に使うのだとしても直感的では無いので、getFocusablesメソッドのオーバロードを増やして貰いたい所だ。(私が勝手に勘違いしている可能性は否定できないが)
これで、アクティビティが使用するビューをフォーカスが遷移する順にアクセスすることができるようになった。
※ツールバーボタンなどと同様の「click-through」インタフェースである。
Click-Through - Apple Human Interface Guidelines