首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ListView中有多个EditText,轻触将焦点放在一个EditText上,焦点会跳到第一个

在ListView中有多个EditText,轻触将焦点放在一个EditText上,焦点会跳到第一个
EN

Stack Overflow用户
提问于 2017-08-03 08:41:17
回答 2查看 783关注 0票数 2

我在ListView中的行中使用了EditTexts。当我点击其中一个EditTexts时,软键盘出现,焦点跳到列表中的第一个EditText,而不是停留在我点击的字段中。

以下是一段视频:

https://youtu.be/ZwuFrX-WWBo

我创建了一个完全精简的应用程序来演示这个问题。完整的代码在这里:https://pastebin.com/YT8rxqKa

我没有做任何事情来改变我代码中的焦点:

代码语言:javascript
复制
@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,这样如果它被不恰当地从他们身上取走,他们就可以重新获得焦点。

这样做可以重新获得焦点,但后来我发现,当文本字段重新获得焦点时,光标会在文本的开头而不是结尾结束,这对我的用户来说是不自然的,也很烦人。

以下是一段视频:

https://youtu.be/A35wLqbuIac

下面是该OnFocusChangeListener的代码。它的工作是对抗愚蠢的机器人移动焦点的行为,但光标在重新获得焦点后被放错了位置。

代码语言:javascript
复制
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(),但是由于文本字段还没有被聚焦,所以选择被忽略了。

EN

回答 2

Stack Overflow用户

发布于 2018-05-09 06:07:21

这就是我的“解决方案”。简而言之:ListView是愚蠢的,当涉及到EditText时,它将永远是一个噩梦,所以我修改了我的片段/适配器代码,以便能够适应ListView布局或ScrollView布局。它只有在行数很少的情况下才有效,因为scrollview实现不能利用延迟加载和视图回收。值得庆幸的是,任何需要在ListView中使用EditTexts的情况下,我的行数很少会超过20行。

当在我的BaseListFragment中膨胀视图时,我通过一个依赖于hasTextFields()方法的方法获得布局id:

代码语言:javascript
复制
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实现。

从那里开始,就需要确保适配器处理ListViewScrollView场景的标准ListView操作。如下所示:

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
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中,我像这样创建适配器:

代码语言:javascript
复制
listener = createClickListener();
adapter = createListAdapter();

if (scrollContainer != null) {
    adapter.setScrollContainer(scrollContainer);
    adapter.setMenuItemClickListener(listener);
    adapter.setupRows();

} else {
    getListView().setOnItemClickListener(listener);
    getListView().setAdapter(adapter);
}

下面是我的scrollfragment.xml以供参考:

代码语言:javascript
复制
<?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>
票数 2
EN

Stack Overflow用户

发布于 2017-08-03 14:42:39

试一次,它对我很有效:

代码语言:javascript
复制
public void setCursorPosition() {
                focusTarget.requestFocus();
                focusTarget.setCursorVisible(true);
                other.setCursorVisible(false);
            } else {
                other.setCursorVisible(true);
                focusTarget.setCursorVisible(false);
            }
        }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45473046

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档