1. ホーム
  2. android

[解決済み] リストビュー内のフォーカス可能な編集テキスト

2022-08-27 03:10:49

質問

これまで6時間ほどこの問題に取り組んできましたが、障害ばかりにぶつかっています。 大まかな前提は、ある行が ListView (それがアダプタによって生成されたものであろうと、ヘッダービューとして追加されたものであろうと)その中に EditText ウィジェットと Button . 私がしたいことは、ジョグボール/矢印を使用して、セレクタを通常のように個々のアイテムに移動できるようにすることです。しかし、特定の行に到達したとき、たとえ明示的に行を特定しなければならないとしても、フォーカスできる子を持ち、セレクタで位置を示す代わりにその子にフォーカスさせたいと思います。

私は多くの可能性を試しましたが、今のところうまくいきません。

のレイアウトを使用しています。

<ListView
    android:id="@android:id/list" 
    android:layout_height="fill_parent" 
    android:layout_width="fill_parent"
    />

ヘッダービューです。

EditText view = new EditText(this);
listView.addHeaderView(view, null, true);

アダプタ内に他の項目がある場合、矢印キーを使用すると、予想通りリストの中で選択項目が上下に移動します。しかし、ヘッダ行に到達すると、セレクタも一緒に表示され EditText にフォーカスする方法がありません。 注意: セレクターの EditText となります。 でフォーカスしますが、これはタッチスクリーンに依存するもので、必須条件ではありません。

ListView は、この点で2つのモードを持っているようです。

1. setItemsCanFocus(true) : セレクタは決して表示されませんが EditText は、矢印を使用するとフォーカスを得ることができます。 フォーカス検索アルゴリズムは予測しにくく、どの項目が選択されているかについての視覚的なフィードバック (どの行にも: フォーカス可能な子がいるかいないか) がないため、両方ともユーザーに予期しない経験をさせる可能性があります。

2. setItemsCanFocus(false) : セレクタは常に非タッチモードで描画され EditText は決してフォーカスを得ることができません -- たとえタップしても。

さらに悪いことに editTextView.requestFocus() を呼び出すとtrueを返しますが、実際にはEditTextにフォーカスを与えていません。

私が思い描いているのは、基本的に1と2のハイブリッドで、リストがもし すべて の項目がフォーカス可能かどうかを設定するリストではなく、フォーカス可能かどうかを シングル を設定し、セレクタが、フォーカスできない項目については行全体を選択し、フォーカスできる子を含む項目についてはフォーカスツリーを走査するように、シームレスに遷移するようにしたいと思います。

誰かいませんか?

どのように解決するのですか?

申し訳ありませんが、私自身の質問に答えました。 それは最も正しく、最もエレガントな解決策ではないかもしれませんが、私のために動作し、かなり強固なユーザー エクスペリエンスを提供します。 2 つの動作がなぜこれほど異なるのかを確認するために ListView のコードを調べ、ListView.java からこれに行き着きました。

    public void setItemsCanFocus(boolean itemsCanFocus) {
        mItemsCanFocus = itemsCanFocus;
        if (!itemsCanFocus) {
            setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        }
    }

ですから setItemsCanFocus(false) を呼び出すと、どの子もフォーカスを得ることができないように、子孫のフォーカスタビリティも設定されます。 このことから、私は mItemsCanFocus を切り替えることができなかった理由を説明しています。

私が今持っているもの。

<ListView
    android:id="@android:id/list" 
    android:layout_height="match_parent" 
    android:layout_width="match_parent"
    android:descendantFocusability="beforeDescendants"
    />

私は beforeDescendants を使用しているのは、セレクタは(子ではなく)ListView自体にフォーカスがあるときにのみ描画されるため、デフォルトの動作はListViewが最初にフォーカスを得てセレクタを描画する必要があるためです。

次に、OnItemSelectedListenerで、セレクタをオーバーライドしたいヘッダービューがわかっているので(任意の位置にフォーカス可能なビューが含まれているかどうかを動的に決定するために多くの作業を必要とします)、子孫フォーカス性を変更し、EditTextにフォーカスを設定することができます。 そして、そのヘッダーから移動するとき、再びそれを変更します。

public void onItemSelected(AdapterView<?> listView, View view, int position, long id)
{
    if (position == 1)
    {
        // listView.setItemsCanFocus(true);

        // Use afterDescendants, because I don't want the ListView to steal focus
        listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        myEditText.requestFocus();
    }
    else
    {
        if (!listView.isFocused())
        {
            // listView.setItemsCanFocus(false);

            // Use beforeDescendants so that the EditText doesn't re-take focus
            listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
            listView.requestFocus();
        }
    }
}

public void onNothingSelected(AdapterView<?> listView)
{
    // This happens when you start scrolling, so we need to prevent it from staying
    // in the afterDescendants mode if the EditText was focused 
    listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}

コメントアウトされた setItemsCanFocus の呼び出しに注目してください。 これらの呼び出しで、私は正しい動作を得ましたが setItemsCanFocus(false) によって、フォーカスが EditText から ListView の外の別のウィジェットに移動し、ListView に戻って次の選択されたアイテムにセレクタが表示され、その移動が邪魔になりました。 ItemsCanFocusの変更を削除し、子孫フォーカスの可否をトグルするだけで、望ましい動作が得られるようになりました。 すべての項目は通常通りセレクタを描画しますが、EditTextのある行に到達すると、代わりにテキストフィールドにフォーカスが当たります。 その後、そのEditTextを抜けると、またセレクタを描画するようになりました。