63

I've got a few EditText fields in a ListView. 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. 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.

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).

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?

... 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)?

My manifest does include android:windowSoftInputMode="stateAlwaysVisible", but the keyboard does not appear until I tap on an 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.

Thanks for any help you can provide!

Kyle Humfeld
  • 1,887
  • 4
  • 23
  • 28
  • Have you tried with a device that has hardware keyboard? That will probably also happen... i THINK emulador does that because it "has" a hardware keyboard. – neteinstein May 11 '11 at 13:35
  • Unfortunately, the only test devices I have access to have soft keyboards. But even if this problem were not to manifest on devices with hardware keyboards (which naturally don't switch between numeric and alpha modes like the soft keyboards do), I'd still want to correct this behavior for all those models that only have soft keyboards. =) – Kyle Humfeld May 11 '11 at 15:39
  • Possible duplicate of [Focusable EditText inside ListView](http://stackoverflow.com/questions/2679948/focusable-edittext-inside-listview) – blahdiblah Nov 01 '13 at 01:04

11 Answers11

131

You need to change in your AndroidManifest.xml

Add android:windowSoftInputMode="adjustPan" in the activity holding the listview. This will solve your problem.

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

Regards

  • This was too good. It would have taken me at least miles to come to this solution. Thanks so much. – Mohit Sethi Jul 03 '12 at 11:49
  • 14
    Well, it does solve the focus-issue. However, it has one other effect as you might see, the view is no longer resizing. – Kenneth Nov 06 '12 at 06:05
  • @Kenneth... That is the point of adjustPan. The view doesn't resize. But it "pans" as best it can to put the focused view in a visible area – Justin Dec 17 '12 at 16:59
  • I get a crash with this solution (IllegalArgumentException) – pcambre May 02 '14 at 20:52
  • I was looking for the reverse, `android:windowSoftInputMode="adjustResize"` is what i needed. – Sheharyar Jan 26 '15 at 03:19
  • The answer from @SoloPilot is decent workaround, this one just change inpun – Happy Dev Jun 30 '16 at 10:35
  • I have a formatting bar align with the top of parent, doing this also hides the top formatting bar . How am i going to not disturb the formatting bar while applying this solution ? any suggestions ? – Hissaan Ali Aug 02 '19 at 17:34
  • I had an Item holding an EditText. This Item was added to an ListView. Once I fokesed the keyboard went crazy because EditText lost focus, keyboard was closed. Then EditText got focus again, keyboard gets opened. And so on... (endless loop) With you're flag android:adjustPan you saved my day! Thanks. – SarotecK Jun 03 '20 at 22:45
  • this change nothing for me, focus is still lost when keyboard opens. The only way to retain focus is user "adjustNothing", that leaves the poor editText in peace, but of course is not a solution. – Anearion Apr 29 '21 at 16:25
  • this is a verbatim copy of https://stackoverflow.com/a/5214261/6451573 – Jean-François Fabre Sep 02 '22 at 21:42
23

Here is how I did it. The onFocusChangeListener() is called several times when you touch a EditText to type text into it. 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()
  6. The leftmost, topmost view gains focus, due to Android nonsense
  7. The leftmost view loses focus, due to requestFocus being called
  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.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
SoloPilot
  • 1,484
  • 20
  • 17
  • 1
    Thanks for such a decent workaround! Should be accepted answer. – Happy Dev Jun 30 '16 at 10:33
  • 5
    It's a shame that Android is so terrible that we have to hack these kinds of workarounds for such basic behavior. Thank you for your solution. – Kenny Wyland Jul 30 '17 at 18:24
  • This is working for me, but introduces another problem. The cursor does jump back to the desired EditText but the cursor is placed at the Start of the text in the textfield instead of at the End which would be natural. – Kenny Wyland Aug 02 '17 at 19:39
  • Faced this issue, and this solution worked like a charm, though I faced it with multiple edit texts inside a recyclerview in dialogfragment. This should be fixed by Android or there has to be some setting in XML. This hack shouldn't be required – nidhi pitroda May 30 '20 at 07:21
  • It solved my 2 hours of solution hunting. For my case, EditText is in InputType="number". Previous EditText input is normal, when previous EditText trigger Enter key, it will send focus to number EditText. Then it straight away jumps all those number EditText and go to normal EditText. A very troublesome issue. Now, this delay approach solve my headache. I tried "adjustpan" in manifest, not helping, if I change to normal text, the issue solved. but I need Number EditText. Thanks for the excellent hack! – scsfdev Jun 09 '23 at 13:22
11

In my case, this is happening because when the ListView resizes, it re-creates all of the list items (i.e. it calls getView() again for each visible list item).

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. A secondary consequence is that when the soft-keyboard appears or disappears I found that I was losing the contents of the EditText.

Because I wanted my view to remain fully accessible (i.e. 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.

You can also grab the text from the previous instance of the EditText at that point and transfer it to the new instance.

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();
    }
}
sheltond
  • 1,877
  • 11
  • 15
  • Thanks!! This solved it for me! I needed to use Resize instead of Pan for softinputmode. – Theos Oct 31 '13 at 22:33
  • This walk-around is good, because sometimes 'adjustPan' makes my actionbar gone, so copy & paste are not visible. I use tags to differentiate multiple editText. Also, I use a second global value - (int) pos to cache the position of the cursor, which makes it more comfortable to users, if necessary. – Yang Mar 26 '14 at 09:40
  • For me, changing the soft input mode was a non-started for me, since I needed it to be do nothing. asking to display keyboard (gain focus) after a short delay (200ms in my case) worked for me. – Gil Moshayof Jan 04 '16 at 12:13
  • Good observation. I was wondering why it was happening on `ListViews` and not on large `ScrollViews`. The widely accepted `adjustPan` solution is actually a cop-out because it may force you to manually hide the keyboard in order to get full access to the rest of the layout. – Bad Loser Nov 14 '20 at 09:56
2

In AndroidManifest.xml use adjustNothing in the activity that contain the views

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

If the editText inside the listView just make sure that you inflate the View in the getView method with this way.


        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.

1

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

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?

Community
  • 1
  • 1
neteinstein
  • 17,529
  • 11
  • 93
  • 123
0

Add android:windowSoftInputMode="adjustResize" in the activity holding the listview or EditText. This will solve your problem.

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

For those who come here with Xamarin or Xamarin.Forms:

I had the same issue as well but only with Android 5.x - all newer Versions including 8.1 worked well.

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 (i.e. it calls getView() again for each visible list item).

My listview was resizing as well and no, Franks solution to set windowSoftInputMode="adjustPan" was no option for me because that means that the keyboard moves the listview partly off the screen.

All I had to do after hours of focus-debugging was setting the cell caching strategy of the 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.

Waescher
  • 5,361
  • 3
  • 34
  • 51
0

In my case, I had called root_scrollview.fullScroll(View.FOCUS_DOWN) on my root ScrollView when Keyboard appears. 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. This solved the problem for me.

Note: Directly calling root_scrollview.scrollTo(0,root_container.bottom) was not working.

Ismail Shaikh
  • 482
  • 4
  • 13
0

This guy had the same problem and more besides. He solved it by using a ScrollView and a LinearLayout instead of a ListView.

Community
  • 1
  • 1
Martin Stone
  • 12,682
  • 2
  • 39
  • 53
  • 11
    This is a workaround, not a solution. This approache sacrifices optimization (through row view reuse) for simplicity. – Ahmed Khalaf Feb 18 '15 at 14:44
0

Convert to 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.

But too late now, 10 years after OP encountered it!

In my case, the disadvantage of switching from SOFT_INPUT_ADJUST_RESIZE to SOFT_INPUT_ADJUST_PAN outweighed the advantage of not losing focus.

Why? ADJUST_RESIZE is the officially preferred approach because ADJUST_PAN blocks part of your view and may prevent scrolling.

But thanks to an earlier answer to this question I became intensely suspicious of ListView.

To prove my suspicions I spent a day converting a complex ListView-based editor to RecyclerView.

I can confirm that soft keyboard state changes no longer affect EditText focus even though I am using ADJUST_RESIZE.

Seemingly painful I know - but perhaps the final result is nicer than sub-classing or tricky workarounds?

Bad Loser
  • 3,065
  • 1
  • 19
  • 31