これまでに約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
をタップするとwillその時点でフォーカスされますが、これは必須ではないタッチスクリーンに依存しています。
ListView
には、明らかに次の2つのモードがあります。
1。 setItemsCanFocus(true)
:セレクターは表示されませんが、EditText
は矢印を使用するとフォーカスを取得できます。フォーカス検索アルゴリズムは予測が難しく、選択された項目に関する視覚的なフィードバック(行にフォーカスできない子があるかどうか)はありません。どちらもユーザーに予期しないエクスペリエンスを提供します。
2。 setItemsCanFocus(false)
:セレクターは常に非タッチモードで描画され、EditText
はタップしてもフォーカスを取得できません。
さらに悪いことに、editTextView.requestFocus()
を呼び出すとtrueが返されますが、実際にはEditTextフォーカスは与えられません。
私が想定しているのは基本的に1と2のハイブリッドで、そこではリスト設定ではなくallアイテムがフォーカス可能であるかどうかではなく、singleにフォーカス可能性を設定したいリスト内のアイテム。これにより、セレクターは、フォーカス不可能なアイテムの行全体の選択から、フォーカス可能な子を含むアイテムのフォーカスツリーの走査までシームレスに移行します。
受験者はいますか?
申し訳ありませんが、私自身の質問に答えました。それは最も正確でエレガントなソリューションではないかもしれませんが、私にとってはうまく機能し、かなり堅実なユーザーエクスペリエンスを提供します。 ListViewのコードを調べて、2つの動作が非常に異なる理由を確認し、ListView.Javaからこれを見つけました。
public void setItemsCanFocus(boolean itemsCanFocus) {
mItemsCanFocus = itemsCanFocus;
if (!itemsCanFocus) {
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
したがって、setItemsCanFocus(false)
を呼び出すときは、子がフォーカスを取得できないように子孫のフォーカス可能性も設定します。これは、ListViewがすべての子へのフォーカスをブロックしていたため、ListViewのOnItemSelectedListenerでmItemsCanFocus
を切り替えることができなかった理由を説明しています。
私が今持っているもの:
<ListView
Android:id="@Android:id/list"
Android:layout_height="match_parent"
Android:layout_width="match_parent"
Android:descendantFocusability="beforeDescendants"
/>
セレクタはListView自体(子ではない)にフォーカスがある場合にのみ描画されるため、beforeDescendants
を使用します。したがって、デフォルトの動作では、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を続行すると、セレクターの描画が再開されます。
これは私を助けました。
マニフェスト内:
<activity Android:name= ".yourActivity" Android:windowSoftInputMode="adjustPan"/>
私のタスクは、クリックすると展開されるListView
を実装することでした。追加のスペースにはEditText
が表示され、ここにテキストを入力できます。アプリは2.2以降で機能する必要があります(これを書いている時点では4.2.2まで)
私はこの投稿や他の見つけられる他の投稿から多くの解決策を試しました。 2.2から4.2.2までのデバイスでテストしました。 2.2以上のすべてのデバイスで満足できるソリューションはなく、各ソリューションにはさまざまな問題がありました。
最終的な解決策を共有したい:
Android:descendantFocusability="afterDescendants"
に設定しますsetItemsCanFocus(true);
に設定しますAndroid:windowSoftInputMode="adjustResize"
に設定します多くの人がadjustPan
を提案しますが、adjustResize
のほうがはるかに優れたux imhoを提供します。 adjustPan
を使用すると、たとえば下のリスト項目が見えなくなります。文書によると(「これは通常、サイズ変更よりも望ましくありません」)。また、ユーザーがソフトキーボードで入力を開始した後の4.0.4では、画面が上にパンします。adjustResize
を使用すると、EditTextフォーカスにいくつかの問題があります。解決策は、このスレッドからrjrjrソリューションを適用することです。怖いですが、そうではありません。そしてそれは動作します。やってみなよ。追加5。EditText
がHoneyCombの以前のバージョンに焦点を合わせたときにアダプターが更新されるため(ビューのサイズ変更のため)、逆ビューで問題が見つかりました: リストビューアイテムのビューを取得/ 2.2の逆順。 4.0.3で動作します
いくつかのアニメーションを実行している場合、サイズ変更が実行されず、アダプターがビューを更新しないように、ハニカムバージョン以前の動作をadjustPan
に変更することができます。このようなものを追加するだけです
if(Android.os.Build.VERSION.SDK_INT < Android.os.Build.VERSION_CODES.HONEYCOMB)
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
これはすべて、2.2〜4.2.2デバイスで許容可能なUXを提供します。この結論に至るまでに少なくとも数時間かかったので、時間を節約できることを願っています。
これは私の命を救った--->
この行を設定
ListView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
次に、アクティビティタグのマニフェストにthis->と入力します
<activity Android:windowSoftInputMode="adjustPan">
あなたのいつもの意図
ビューのリサイクルを行わない短いリストでこれを試しています。ここまでは順調ですね。
XML:
<RitalinLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
>
<ListView
Android:id="@+id/cart_list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:scrollbarStyle="outsideOverlay"
/>
</RitalinLayout>
Java:
/**
* It helps you keep focused.
*
* For use as a parent of {@link Android.widget.ListView}s that need to use EditText
* children for inline editing.
*/
public class RitalinLayout extends FrameLayout {
View sticky;
public RitalinLayout(Context context, AttributeSet attrs) {
super(context, attrs);
ViewTreeObserver vto = getViewTreeObserver();
vto.addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override public void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (newFocus == null) return;
View baby = getChildAt(0);
if (newFocus != baby) {
ViewParent parent = newFocus.getParent();
while (parent != null && parent != parent.getParent()) {
if (parent == baby) {
sticky = newFocus;
break;
}
parent = parent.getParent();
}
}
}
});
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override public void onGlobalLayout() {
if (sticky != null) {
sticky.requestFocus();
}
}
});
}
}
この投稿は私のキーワードと完全に一致していました。検索EditTextと検索ボタンを持つListViewヘッダーがあります。
最初のフォーカスを失った後にEditTextにフォーカスを与えるために私が見つけた唯一のHACKは次のとおりです。
searchText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// LOTS OF HACKS TO MAKE THIS WORK.. UFF...
searchButton.requestFocusFromTouch();
searchText.requestFocus();
}
});
多くの時間を失い、それは本当の修正ではありません。それが誰かの助けになることを願っています。
リストが動的でフォーカス可能なウィジェットを含む場合、正しいオプションはListView IMOの代わりにRecyclerViewを使用することです。
adjustPan
、FOCUS_AFTER_DESCENDANTS
を設定する回避策、またはフォーカスされた位置を手動で記憶する回避策は、まさに回避策です。コーナーケースがあります(スクロール+ソフトキーボードの問題、EditTextでのキャレットの変更)。彼らは、notifyDataSetChanged
中にListViewがビューを作成/破棄するという事実を変更しませんen masse。
RecyclerViewでは、個々の挿入、更新、削除について通知します。フォーカスされたビューは再作成されていないため、フォームコントロールがフォーカスを失う問題はありません。追加のボーナスとして、RecyclerViewはリストアイテムの挿入と削除をアニメーション化します。
以下は、RecyclerView
の使用を開始する方法に関する公式ドキュメントの例です。 開発者ガイド-RecyclerViewでリストを作成する
Android:windowSoftInputMode="stateAlwaysHidden"
inマニフェストアクティビティまたはxmlを使用すると、キーボードフォーカスが失われる場合があります。そのため、最初にxmlおよびマニフェストでそのプロパティを確認します(存在する場合は削除します)。サイドアクティビティAndroid:windowSoftInputMode="adjustPan"
のマニフェストファイルにこれらのオプションを追加し、xmlのリストビューにこのプロパティを追加した後Android:descendantFocusability="beforeDescendants"
別の解決策を見つけました。私はそれが解決策というよりもハッキングであると信じていますが、それはAndroid 2.3.7とAndroid 4.3で動作します(私はその古き良きD-padさえテストしました)
通常どおりウェブビューを初期化し、これを追加します:(Michael Biermanに感謝)
listView.setItemsCanFocus(true);
GetView呼び出し中:
editText.setOnFocusChangeListener(
new OnFocusChangeListener(View view,boolean hasFocus){
view.post(new Runnable() {
@Override
public void run() {
view.requestFocus();
view.requestFocusFromTouch();
}
});
これを試してみてください
Android:windowSoftInputMode="adjustNothing"
の中に
アクティビティ
マニフェストのセクション。はい、何も調整しません。つまり、IMEが開いているとき、editTextは元の場所にとどまります。しかし、それは焦点を失うという問題をまだ完全に解決する少し不便です。
最も重要な部分は、リストセルでfocusを機能させることです。特にGoogle TVのリストでは、これが不可欠です。
setItemsCanFocusリストビューのメソッドはトリックを行います:
...
mPuzzleList = (ListView) mGameprogressView.findViewById(R.id.gameprogress_puzzlelist);
mPuzzleList.setItemsCanFocus(true);
mPuzzleList.setAdapter(new PuzzleListAdapter(ctx,PuzzleGenerator.getPuzzles(ctx, getResources(), version_lite)));
...
リストセルxmlは次のように始まります。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/puzzleDetailFrame"
Android:focusable="true"
Android:nextFocusLeft="@+id/gameprogress_lessDetails"
Android:nextFocusRight="@+id/gameprogress_reset"
...
nextFocusLeft/RightもD-Padナビゲーションにとって重要です。
詳細については、他のすばらしい回答をご覧ください。
もう1つの簡単な解決策は、ListAdapterのgetView(..)メソッドでonClickListenerを定義することです。
public View getView(final int position, View convertView, ViewGroup parent){
//initialise your view
...
View row = context.getLayoutInflater().inflate(R.layout.list_item, null);
...
//define your listener on inner items
//define your global listener
row.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
doSomethingWithViewAndPosition(v,position);
}
});
return row;
そうすれば、行がクリック可能になり、内部ビューも:)