简体   繁体   English

当软键盘出现时,它使我的 EditText 字段失去焦点

[英]When the soft keyboard appears, it makes my EditText field lose focus

I've got a few EditText fields in a ListView.我在 ListView 中有一些 EditText 字段。 When I tap on one of the EditText fields, the keyboard slides into view (as it should), but the EditText field I tapped loses focus.当我点击 EditText 字段之一时,键盘会滑入视图(应该如此),但我点击的 EditText 字段失去焦点。 I've tried using various InputMethodManager methods to make the keyboard start out in view (in order to get around the problem rather than truly solve it), but that didn't work - the keyboard was not in view when the Activity appeared.我尝试使用各种 InputMethodManager 方法使键盘在视图中启动(为了解决问题而不是真正解决它),但这不起作用 - 当 Activity 出现时键盘不在视图中。

The EditText's type is number , and when the keyboard is sliding in, it is a number keyboard, but when it finishes sliding and the EditText loses focus, it changes to the alphabetical keyboard (which reinforces the idea that the EditText no longer has focus). EditText 的类型是number ,当键盘滑入时,它是一个数字键盘,但是当它完成滑动并且 EditText 失去焦点时,它变为字母键盘(这加强了 EditText 不再有焦点的想法) .

My questions are these:我的问题是这些:

1) How can I make the selection of my EditText field and the subsequent sliding in of the soft keyboard not make my EditText lose focus? 1) 如何使我的 EditText 字段的选择和软键盘的后续滑入不会使我的 EditText 失去焦点?

... failing that... ……失败了……

2) How can I make the keyboard start out in view so it never has to slide in (thus avoiding the behavior I find so objectionable)? 2) 我怎样才能让键盘从视野中开始,这样它就不必滑入(从而避免我觉得如此令人反感的行为)?

My manifest does include android:windowSoftInputMode="stateAlwaysVisible" , but the keyboard does not appear until I tap on an EditText.我的清单确实包括android:windowSoftInputMode="stateAlwaysVisible" ,但在我点击 EditText 之前键盘不会出现。 This ignoring of the 'stateAlwaysVisible' attribute seems to only occur in the emulator - on my provisioned device, it is honored so question number 2 above does work on the device... but not in the emulator.这种对 'stateAlwaysVisible' 属性的忽略似乎只发生在模拟器中 - 在我配置的设备上,它很荣幸,所以上面的问题 2 确实适用于设备......但不适用于模拟器。

Thanks for any help you can provide!感谢您的任何帮助,您可以提供!

You need to change in your AndroidManifest.xml您需要在 AndroidManifest.xml 中进行更改

Add android:windowSoftInputMode="adjustPan" in the activity holding the listview.在持有列表视图的活动中添加 android:windowSoftInputMode="adjustPan"。 This will solve your problem.这将解决您的问题。

    <activity android:name=".MyEditTextInListView"
              android:label="@string/app_name"
              android:windowSoftInputMode="adjustPan">

Regards问候

Here is how I did it.这是我如何做到的。 The onFocusChangeListener() is called several times when you touch a EditText to type text into it.当您触摸EditText以在其中键入文本时, onFocusChangeListener()会被多次调用。 The sequence is:顺序是:

  1. If focus was on a different view, then that view loses focus如果焦点在不同的视图上,则该视图失去焦点
  2. The target gains focus目标获得焦点
  3. Soft keyboard pops up.弹出软键盘。
  4. This causes the target to lose focus这会导致目标失去焦点
  5. The code detects this situation and calls target.requestFocus()代码检测到这种情况并调用 target.requestFocus()
  6. The leftmost, topmost view gains focus, due to Android nonsense由于 Android 废话,最左边、最上面的视图获得焦点
  7. The leftmost view loses focus, due to requestFocus being called由于 requestFocus 被调用,最左边的视图失去焦点
  8. Target finally gains focus目标终于获得焦点

    ////////////////////////////////////////////////////////////////// private final int minDelta = 300; // threshold in ms private long focusTime = 0; // time of last touch private View focusTarget = null; 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 > minDelta) { focusTime = t; focusTarget = view; } } else { // lost focus if (delta <= minDelta && view == focusTarget) { focusTarget.post(new Runnable() { // reset focus to target public void run() { focusTarget.requestFocus(); } }); } } } };

The code above works well for the keyboard pop-ups.上面的代码适用于键盘弹出窗口。 However, it does not detect the speech-to-text pop-up.但是,它不会检测到语音到文本的弹出窗口。

In my case, this is happening because when the ListView resizes, it re-creates all of the list items (ie it calls getView() again for each visible list item).在我的情况下,发生这种情况是因为当 ListView 调整大小时,它会重新创建所有列表项(即它为每个可见列表项再次调用 getView())。

Because the EditText is within the layout that I'm returning from getView(), this means that it's a different instance of EditText than the one which had the focus previously.因为 EditText 位于我从 getView() 返回的布局内,这意味着它是 EditText 的一个不同实例,而不是以前具有焦点的实例。 A secondary consequence is that when the soft-keyboard appears or disappears I found that I was losing the contents of the EditText.第二个后果是当软键盘出现或消失时,我发现我丢失了 EditText 的内容。

Because I wanted my view to remain fully accessible (ie I want it to be resized instead of hidden behind the keyboard window with some parts not accessible), I couldn't use Frank's answer, which otherwise seems like the best approach.因为我希望我的视图保持完全可访问(即我希望它被调整大小而不是隐藏在键盘窗口后面,某些部分不可访问),我不能使用弗兰克的答案,否则这似乎是最好的方法。

I solved this by using an OnFocusChangeListener on the EditText to record the timestamp when the focus was lost, and then in getView() when recreating the list item, if the current time is within some threshold from when the focus was lost, call requestFocus() to give it back to the EditText in question.我通过在 EditText 上使用 OnFocusChangeListener 记录焦点丢失时的时间戳来解决这个问题,然后在重新创建列表项时在 getView() 中,如果当前时间在焦点丢失时的某个阈值内,请调用 requestFocus( ) 将其返回给有问题的 EditText。

You can also grab the text from the previous instance of the EditText at that point and transfer it to the new instance.您还可以在那时从 EditText 的前一个实例中获取文本并将其传输到新实例。

private class MyAdapter<Type> extends ArrayAdapter<String>
    implements OnFocusChangeListener
{
    private EditText mText;
    private long mTextLostFocusTimestamp;
    private LayoutInflater mLayoutInflater;

    public MyAdapter(Context context, int resource, int textResourceId, ArrayList<String> data, LayoutInflater li) {
        super(context, resource, textResourceId, data);
        mLayoutInflater = li;
        mTextLostFocusTimestamp = -1;
    }

    private void reclaimFocus(View v, long timestamp) {
        if (timestamp == -1)
            return;
        if ((System.currentTimeMillis() - timestamp) < 250)
            v.requestFocus();
    }

    @Override public View getView (int position, View convertView, ViewGroup parent)
    {
        View v = mLayoutInflater.inflate(R.layout.mylayout, parent, false);

        EditText newText = (EditText) v.findViewById(R.id.email);
        if (mText != null)
            newText.setText(mText.getText());
        mText = newText;
        mText.setOnFocusChangeListener(this);
        reclaimFocus(mText, mTextLostFocusTimestamp);

        return v;
    }

    @Override public void onFocusChange(View v, boolean hasFocus) {
        if ((v == mText) && !hasFocus)
            mTextLostFocusTimestamp = System.currentTimeMillis();
    }
}

In AndroidManifest.xml use adjustNothing in the activity that contain the views在 AndroidManifest.xml 中,在包含视图的活动中使用 adjustNothing

<activity
            android:name=".ActivityName"
            android:windowSoftInputMode="adjustNothing">

If the editText inside the listView just make sure that you inflate the View in the getView method with this way.如果 listView 中的 editText 只是确保使用这种方式在 getView 方法中膨胀 View 。


        if (convertView == null)
        convertView = LayoutInflater.from(context).inflate(R.layout.yourItemListLayout,
                parent, false);   

Edit: this work for some mobiles not all I use the answer from Mr.Frank above.编辑:这项工作适用于某些手机,并非所有我都使用上面 Mr.Frank 的答案。

You should test this code on a device with hardware keyboard always visible.您应该在硬件键盘始终可见的设备上测试此代码。 The behavior may also happen here.这种行为也可能发生在这里。

To avoid this you can have the keyboard always visible.. but that is not very easy as you can see by this thread:为避免这种情况,您可以让键盘始终可见。

https://groups.google.com/forum/#!topic/android-developers/FyENeEdmYC0 https://groups.google.com/forum/#!topic/android-developers/FyENeEdmYC0

Theoretically you may have to create your own Android keyboard (although using as base the stock Android keyboard) as described here: Android: How to make the keypad always visible?从理论上讲,您可能需要创建自己的 Android 键盘(尽管使用 Android 键盘作为基础),如下所述: Android:如何使键盘始终可见?

Add android:windowSoftInputMode="adjustResize" in the activity holding the listview or EditText.在包含列表视图或 EditText 的活动中添加 android:windowSoftInputMode="adjustResize"。 This will solve your problem.这将解决您的问题。

<activity android:name=".MainActivity"
        android:windowSoftInputMode="adjustResize">
</activity>

For those who come here with Xamarin or Xamarin.Forms:对于那些带着 Xamarin 或 Xamarin.Forms 来到这里的人:

I had the same issue as well but only with Android 5.x - all newer Versions including 8.1 worked well.我也遇到了同样的问题,但仅限于 Android 5.x - 包括 8.1 在内的所有较新版本都运行良好。

Obviously sheltond was right by saying:显然,谢尔顿说得对:

In my case, this is happening because when the ListView resizes, it re-creates all of the list items (ie it calls getView() again for each visible list item).在我的情况下,发生这种情况是因为当 ListView 调整大小时,它会重新创建所有列表项(即它为每个可见列表项再次调用 getView())。

My listview was resizing as well and no, Frank s solution to set windowSoftInputMode="adjustPan" was no option for me because that means that the keyboard moves the listview partly off the screen.我的列表视图也在调整大小,不,弗兰克设置windowSoftInputMode="adjustPan"的解决方案对我来说不是选择,因为这意味着键盘将列表视图部分移出屏幕。

All I had to do after hours of focus-debugging was setting the cell caching strategy of the Xamarin Forms ListView:经过数小时的焦点调试后,我所要做的就是设置 Xamarin Forms ListView 的单元格缓存策略:

From

CachingStrategy="RecycleElement"

To

CachingStrategy="RetainElement"

This will stop the cells from being recreated.这将阻止重新创建单元格。 However, this might result in bad performance and high memory consumption for huge lists.但是,这可能会导致巨大的列表性能不佳和内存消耗高。 Be aware.意识到。

In my case, I had called root_scrollview.fullScroll(View.FOCUS_DOWN) on my root ScrollView when Keyboard appears.就我而言,当键盘出现时,我在我的根 ScrollView 上调用了root_scrollview.fullScroll(View.FOCUS_DOWN) I replaced it with我用

login_scrollview.post(new Runnable() { 
    @Override
    public void run() {
        root_scrollview.scrollTo(0,root_container.bottom)
    }
});

where root_container is the immediate child of root_scrollview.其中 root_container 是 root_scrollview 的直接子级。 This solved the problem for me.这为我解决了这个问题。

Note: Directly calling root_scrollview.scrollTo(0,root_container.bottom) was not working.注意:直接调用root_scrollview.scrollTo(0,root_container.bottom)不起作用。

This guy had the same problem and more besides. 这家伙有同样的问题,而且还有更多。 He solved it by using a ScrollView and a LinearLayout instead of a ListView.他通过使用 ScrollView 和 LinearLayout 而不是 ListView 解决了这个问题。

Convert to RecyclerView转换为 RecyclerView

I believe that loss of focus on show or hide of the keyboard is not expected behavior and either should have been (or should be) a reported Android issue.我相信失去对键盘显示隐藏的关注不是预期的行为,并且应该是(或应该是)报告的 Android 问题。

But too late now, 10 years after OP encountered it!但是现在已经晚了,10年后OP遇到了!

In my case, the disadvantage of switching from SOFT_INPUT_ADJUST_RESIZE to SOFT_INPUT_ADJUST_PAN outweighed the advantage of not losing focus.在我的情况下,开关的缺点SOFT_INPUT_ADJUST_RESIZESOFT_INPUT_ADJUST_PAN胜过不失去焦点的优势。

Why?为什么? ADJUST_RESIZE is the officially preferred approach because ADJUST_PAN blocks part of your view and may prevent scrolling. ADJUST_RESIZE官方首选的方法,因为ADJUST_PAN阻止部分视图并可能阻止滚动。

But thanks to an earlier answer to this question I became intensely suspicious of ListView .但是由于早先对这个问题的回答,我对ListView强烈的怀疑。

To prove my suspicions I spent a day converting a complex ListView -based editor to RecyclerView .为了证明我的怀疑,我花了一天时间将一个复杂的基于ListView的编辑器转换为RecyclerView

I can confirm that soft keyboard state changes no longer affect EditText focus even though I am using ADJUST_RESIZE .我可以确认软键盘状态更改不再影响EditText焦点,即使我正在使用ADJUST_RESIZE

Seemingly painful I know - but perhaps the final result is nicer than sub-classing or tricky workarounds?我知道看起来很痛苦 - 但也许最终结果比子分类或棘手的解决方法更好?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM