我在ListView中的行中使用了EditTexts。当我点击其中一个EditTexts时,软键盘出现,焦点跳到列表中的第一个EditText,而不是停留在我点击的字段中。
以下是一段视频:
我创建了一个完全精简的应用程序来演示这个问题。完整的代码在这里:https://pastebin.com/YT8rxqKa
我没有做任何事情来改变我代码中的焦点:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.cell_textfield, parent, false);
}
TextView label = (TextView) convertView.findViewById(R.id.textview1);
EditText textfield = (EditText) convertView.findViewById(R.id.textview2);
String text = String.format("Row %d", position);
label.setText(text);
textfield.setText(text);
return convertView;
}我发现another post on StackOverflow为这种愚蠢的安卓行为提供了一个变通办法,包括在所有的文本字段上放置一个OnFocusChangedListener,这样如果它被不恰当地从他们身上取走,他们就可以重新获得焦点。
这样做可以重新获得焦点,但后来我发现,当文本字段重新获得焦点时,光标会在文本的开头而不是结尾结束,这对我的用户来说是不自然的,也很烦人。
以下是一段视频:
下面是该OnFocusChangeListener的代码。它的工作是对抗愚蠢的机器人移动焦点的行为,但光标在重新获得焦点后被放错了位置。
View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
long t = System.currentTimeMillis();
long delta = t - focusTime;
if (hasFocus) { // gained focus
if (delta > minDeltaForReFocus) {
focusTime = t;
focusTarget = view;
}
}
else { // lost focus
if (delta <= minDeltaForReFocus && view == focusTarget) {
focusTarget.post(new Runnable() { // reset focus to target
public void run() {
Log.d("BA", "requesting focus");
focusTarget.requestFocus();
}
});
}
}
}
};我讨厌不得不把创可贴放在创可贴上,试图让Android表现得像它自然应该表现的那样,但我会接受我能得到的。
1)有没有什么办法可以在源代码上解决这个问题,而不需要使用OnFocusChangeListener?
2)如果(1)不可能,那么我如何确保当我强制焦点回到正确的字段时,我确保光标放在末尾?我尝试在requestFocus()之后使用setSelection(),但是由于文本字段还没有被聚焦,所以选择被忽略了。
发布于 2018-05-09 06:07:21
这就是我的“解决方案”。简而言之:ListView是愚蠢的,当涉及到EditText时,它将永远是一个噩梦,所以我修改了我的片段/适配器代码,以便能够适应ListView布局或ScrollView布局。它只有在行数很少的情况下才有效,因为scrollview实现不能利用延迟加载和视图回收。值得庆幸的是,任何需要在ListView中使用EditTexts的情况下,我的行数很少会超过20行。
当在我的BaseListFragment中膨胀视图时,我通过一个依赖于hasTextFields()方法的方法获得布局id:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(), container, false);
return view;
}
public boolean hasTextfields() {
return false;
}
public int getLayoutId() {
if (hasTextfields()) {
return R.layout.scrollfragment;
} else {
return R.layout.listfragment;
}
}在我的BaseListFragment的各个子类中,如果我的一个字段中需要有一个EditText,我只需覆盖hasTextFields()方法以返回true,然后我的片段/适配器切换到使用基本的scrollview实现。
从那里开始,就需要确保适配器处理ListView和ScrollView场景的标准ListView操作。如下所示:
public void notifyDataSetChanged() {
// If scrollContainer is not null, that means we're in a ScrollView setup
if (this.scrollContainer != null) {
// intentionally not calling super
this.scrollContainer.removeAllViews();
this.setupRows();
} else {
// use the real ListView
super.notifyDataSetChanged();
}
}
public void setupRows() {
for (int i = 0; i < this.getCount(); i++) {
View view = this.getView(i, null, this.scrollContainer);
view.setOnClickListener(myItemClickListener);
this.scrollContainer.addView(view);
}
}单击侦听器提出的一个问题是,ListView需要一个AdapterView.OnItemClickListener,但ScrollView中的任意View需要一个简单的View.OnClickListener。因此,我让我的ItemClickListener也实现了View.OnClickListener,然后将OnClick分派给OnItemClick方法:
public class MyItemClickListener implements AdapterView.OnItemClickListener, View.OnClickListener {
@Override
public void onClick(View v) {
// You can either have your Adapter set the tag on the View to be its position
// or you could have your click listener use v.getParent() and iterate through
// the children to find the position. I find its faster and easier to have my
// adapter set the Tag on the view.
int position = v.getTag();
this.onItemClick(null, v, config.getPosition(), 0);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ...
}
}然后在MyEditTextListFragment中,我像这样创建适配器:
listener = createClickListener();
adapter = createListAdapter();
if (scrollContainer != null) {
adapter.setScrollContainer(scrollContainer);
adapter.setMenuItemClickListener(listener);
adapter.setupRows();
} else {
getListView().setOnItemClickListener(listener);
getListView().setAdapter(adapter);
}下面是我的scrollfragment.xml以供参考:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:clickable="true"
>
<!--
The following LinearLayout as a focus catcher that won't cause the keyboard to
show without it, the virtual keyboard shows up immediately/always which means we
never get to the enjoy the full size of our screen while scrolling, and
that sucks.
-->
<LinearLayout
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="0px"
android:layout_height="0px"/>
<!--
This ListView is still included in the layout but set to visibility=gone. List
fragments require a standard ListView in the layout, so this gets us past that
check and allows us to use the same adapter code in both listview and scrollview
situations.
-->
<ListView android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:background="@null"
android:layout_alignParentTop="true"
android:descendantFocusability="afterDescendants"
android:visibility="gone"
/>
<!--
This scrollview will act as our fake listview so that we don't have to deal with
all the stupid crap that comes along with having EditTexts inside a ListView.
-->
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="afterDescendants"
>
<LinearLayout
android:id="@+id/scrollContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
</LinearLayout>
</ScrollView>
</RelativeLayout>发布于 2017-08-03 14:42:39
试一次,它对我很有效:
public void setCursorPosition() {
focusTarget.requestFocus();
focusTarget.setCursorVisible(true);
other.setCursorVisible(false);
} else {
other.setCursorVisible(true);
focusTarget.setCursorVisible(false);
}
}https://stackoverflow.com/questions/45473046
复制相似问题