ListView
中有一些行(无论是由适配器生成还是作为标题视图添加),其中包含EditText
小部件和Button
。我想要做的就是能够使用jogball /箭头,将选择器导航到正常的单个项目,但是当我到达特定行时 - 即使我必须明确地识别行 - 它具有可聚焦孩子,我希望那个孩子获得焦点而不是用选择器指示位置。
我尝试了很多种可能性,到目前为止还没有运气。
布局:
<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);
假设适配器中还有其他项目,使用箭头键将按预期在列表中上/下移动选择;但是当到达标题行时,它也会与选择器一起显示,并且无法使用jogball聚焦到EditText
。注意:点击EditText
会将焦点集中在那一点上,但这取决于触摸屏,这不是必需的。
ListView
显然在这方面有两种模式:
1. setItemsCanFocus(true)
:永远不会显示选择器,但使用箭头时EditText
可以获得焦点。焦点搜索算法难以预测,并且没有选择项目的视觉反馈(在任何行上:是否有可聚焦的孩子),这两者都可以给用户带来意想不到的体验。
2. setItemsCanFocus(false)
:选择器始终以非触摸模式绘制,EditText
永远无法获得焦点 - 即使您点按它也是如此。
更糟糕的是,调用editTextView.requestFocus()
会返回true,但实际上并没有给EditText提供焦点。
我想象的基本上是1&amp;的混合体。 2,如果所有项目都是可聚焦的,而不是列表设置,我想在列表中设置单个项目的可聚焦性,以便选择器从无缝转换为不可聚焦的项目选择整行,并为包含可聚焦儿童的项目遍历焦点树。
任何参赛者?
答案 0 :(得分:101)
抱歉,回答了我自己的问题。它可能不是最正确或最优雅的解决方案,但它适用于我,并提供非常可靠的用户体验。我查看了ListView的代码,看看为什么这两个行为如此不同,并从ListView.java中看到了这个:
public void setItemsCanFocus(boolean itemsCanFocus) {
mItemsCanFocus = itemsCanFocus;
if (!itemsCanFocus) {
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
因此,在调用setItemsCanFocus(false)
时,它还设置了后代可聚焦性,这样任何孩子都无法获得焦点。这解释了为什么我不能只在ListView的OnItemSelectedListener中切换mItemsCanFocus
- 因为ListView阻止了对所有孩子的焦点。
我现在拥有的:
<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时,它再次开始绘制选择器。
答案 1 :(得分:95)
这对我有帮助 在你的清单中:
<activity android:name= ".yourActivity" android:windowSoftInputMode="adjustPan"/>
答案 2 :(得分:17)
我的任务是实施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
,您将获得隐藏的底部列表项。文档建议(&#34;这通常不如调整大小&#34;)。同样在4.0.4用户开始在软键盘上打字后,屏幕平移到顶部。adjustResize
EditText焦点存在一些问题。解决方案是从该线程应用rjrjr解决方案。它看起来很麻烦,但事实并非如此。它有效。试一试。 附加5。由于适配器正在刷新(因为视图调整大小),当EditText
专注于预装HoneyComb版本时,我发现了反向视图的问题:
getting View for ListView item / reverse order on 2.2; works on 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。 希望它能节省一些时间,因为我花了至少几个小时来得出这个结论。
答案 3 :(得分:9)
这拯救了我的生命---&gt;
设置此行
ListView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
然后在您的活动标签清单中输入此 - &gt;
<activity android:windowSoftInputMode="adjustPan">
你通常的意图
答案 4 :(得分:7)
我们在一个没有进行任何视图回收的简短列表上尝试这个。到目前为止一切都很好。
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>
爪哇:
/**
* 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();
}
}
});
}
}
答案 5 :(得分:4)
这篇文章与我的关键字完全匹配。我有一个ListView标头,带有搜索EditText和搜索按钮。
为了在失去初始焦点后将焦点放在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();
}
});
失去了很多时间,这不是一个真正的解决方案。希望它可以帮助一些人。
答案 6 :(得分:2)
如果列表是动态的并且包含可聚焦的小部件,那么正确的选项是使用 RecyclerView 而不是ListView IMO。
设置adjustPan
,FOCUS_AFTER_DESCENDANTS
或手动记住重点位置的变通方法确实只是解决方法。他们有角落案例(滚动+软键盘问题,插入符号在EditText中更改)。他们不会改变ListView在notifyDataSetChanged
期间创建/销毁视图 en masse 这一事实。
使用RecyclerView,您可以通知各个插入,更新和删除。焦点视图没有被重新创建,因此表单控件没有问题失去焦点。作为额外的奖励,RecyclerView动画列表项插入和删除。
以下是官方文档中有关如何开始使用RecyclerView
的示例:Developer guide - Create a List with RecyclerView
答案 7 :(得分:1)
有些时候在清单活动或xml中使用<android version="1.0.16.2">
<blackberry10 version="1.0.1.2"/>
<iphone version="1.0.16.2">
时,它会丢失键盘焦点。因此,首先检查xml和manifest中的属性,如果有,只需将其删除即可。将这些选项添加到旁边活动android:windowSoftInputMode="stateAlwaysHidden"
中的清单文件后,将此属性添加到xml android:windowSoftInputMode="adjustPan"
中的listview
答案 8 :(得分:0)
另一个简单的解决方案是在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;
这样你的行可以点击,你的内部视图也是:)
答案 9 :(得分:0)
最重要的部分是让焦点为列表单元格工作。 特别是对于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导航也很重要。
有关详细信息,请查看其他很多答案。
答案 10 :(得分:0)
我刚刚找到另一种解决方案。我相信它更像是一个黑客而不是一个解决方案,但它适用于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();
}
});
答案 11 :(得分:0)
试试这个
android:windowSoftInputMode="adjustNothing"
中的
你的清单的活性
部分。 是的,它会调整nothings,这意味着editText将保持IME打开时的位置。但这只是一点点不便仍然完全解决了失去焦点的问题。
答案 12 :(得分:0)
就我而言,列表视图中有14个输入的编辑文本。我面临的问题是,当键盘打开时,编辑文本的焦点丢失,滚动布局,并且一旦用户键盘向下看不到焦点视图,便会遇到问题。这对用户体验不利。我不能使用windowSoftInputMethod =“ adjustPan”。因此,经过如此多的搜索,我发现了一个link,可以通过使用LinearLayout和scrollView来扩大自定义布局并在视图上将数据设置为适配器,并且可以很好地满足我的情况。