ChatGPT解决这个技术问题 Extra ChatGPT

Android: EditText in Dialog doesn't pull up soft keyboard

So I've got what seems to be a common problem, which is that the EditText in my dialog box doesn't show up when it gets focus. I've seen several workarounds, such as in this thread, this one and this one (and many more), but I have never seen a satisfactory explanation for why this is happening in the first place.

I would much prefer to have android use its own default behavior for EditTexts than to build my own, but it seems like everyone (in those threads) has accepted that the default behavior for EditTexts in Dialogs is to just give a cursor and no keyboard. Why would that be?

For the record, none of these workarounds seem to be working for me - the closest I've been able to come is forcing a keyboard to appear underneath the dialog box (using InputMethodManager.toggleSoftKeyboard(*)). My particular configuration is API15, the EditText shows up in a footer on a ListView within an AlertDialog. The EditText android:focusable="true" is set, and onFocusChangeListener is receiving focus events.

Edit:

As requested, here is the specific code snippet that I'm working with. I won't bother with the whole layout, but in this specific application, the EditText appears in response to pressing a button on the dialog (similar to an action view). It is contained in a RelativeLayout which by default has visibility "gone":

 <RelativeLayout 
       android:id="@+id/relLay"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_centerVertical="true"
       android:visibility="gone"
       android:layout_marginTop="5dp"
       android:layout_marginBottom="5dp">

        <ImageButton
            android:id="@+id/cancelBut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:background="@color/transparent"
            android:src="@drawable/cancelButton" 
            android:layout_margin="5dp"/>

        <ImageButton
            android:id="@+id/okBut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/cancelBut"
            android:background="@color/transparent"
            android:src="@drawable/okButton"
            android:layout_margin="5dp" />

        <EditText 
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:focusable="true"
            android:layout_toLeftOf="@id/okBut"/>
   </RelativeLayout>

The code which builds this sets the visibility of the relativeLayout to "Visible" (and hides the other UI elements). This should be enough to pull up the keyboard when the EditText gets focused, based on my experience with EditText. However, for some reason this is not the case. I can set the following onFocusChangeListener:

    edit_text.setOnFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                // For whatever reason we need to request a soft keyboard.
                    InputMethodManager imm = (InputMethodManager)dlg.getWindow().getContext().getSystemService(_Context.INPUT_METHOD_SERVICE);
                    if(hasFocus)
                        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    Log.v("DialogProblem", "Focus requested, " + (hasFocus?"has focus.":"doesn't have focus."));
                }
            }
        });

Using this configuration, when I first enter the EditText, the onFocusChangedListener triggers, and generates a log that invariably looks like this:

Focus requested, has focus.
Focus requested, doesn't have focus.
Focus requested, has focus.

The keyboard shows up and then disappears, probably because I toggle it twice, but even when I make sure it stays up, it's behind the dialog window (in a greyed out area), and there's no way to get to it without closing the dialog.

That said, I'd like to emphasize that even though I may be able to get this work-around to work, I'm primarily interested in finding a simple reason why the EditText isn't triggering in the first place, and why this seems to be so commonplace!

Would you mind posting the relevant code snippet (where you set focus, add a focus listener, etc)?
I can (and will when I get back to a computer), but I think my wider question doesn't involve a focus listener. I'm wondering why it seems to be a common problem that edit text in a dialog doesn't open the keyboard. While I'd be happy to use a kluge if that's the way to do it, but I'd like to know why such a thing is necessary.

P
Paul

OK, so after reading a lot, I have figured out why this is a problem, and I do not need to use any workarounds.

The problem seems to be (at least in my case), that since the place where you enter text is hidden initially (or nested or something), AlertDialog is automatically setting the flag WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (or some combination of that and WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) so that things don't trigger a soft input to show up.

The way that I've found to fix this is to add the following line after the dialog has been created:

dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

Once this is done, the EditText acts like a normal EditText, no kludges or workarounds necessary.


When I tried to clear the flags after the Create it didn't worked. It worked only when I used it like this: Dialog = builder.create(); Dialog.show(); Dialog.getWindow().clearFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); Dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@AlexanderFragotsis after trying so many different solutions on stackoverflow, your comment is the only one that works! Thank you!
SOFT_INPUT_STATE_‌VISIBLE didn't work for me. I used SOFT_INPUT_STATE_ALWAYS_VISIBLE and then it worked. Just putting it out there if anyone else has the same problem
Yeah, I couldnt get SOFT_INPUT_STATE_VISIBLE to work either but _ALWAYS_VISIBLE works. anyone know whats going on there?
Very important to do the clearFlags() after show(), thanks @AlexanderFragotsis
G
Gian U.

I have the same problem in my own app. If you are developing for API level >= 8 you can use this snippet:

dialog.setOnShowListener(new OnShowListener() {
    @Override
     public void onShow(DialogInterface dialog) {
         InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
         imm.showSoftInput(textEdit, InputMethodManager.SHOW_IMPLICIT);
    }
});

I haven't found a solution for lower API levels...

BTW: This snippet doesn't always work on emulator. I don't know why.


I'm not so much interested in this specific workaround as I am interested in why it's not working in the first place. Additionally, I don't actually want the keyboard to show up with the dialog, I want it to show up when the EditText gains focus, like the behavior of a normal EditText.
This worked for me. Just use AlertDialog dialog = builder.create(); before and dialog.show(); after the above if you're using AlertDialog.Builder
This is the only one that worked for me. I also don't think it's a workaround, it makes sense when you read it with the answer below quoting from the Android docs about why you can't request focus until the dialog is actually showing.
p
philips77

If you read the AlertDialog documentation you'll find there:

The AlertDialog class takes care of automatically setting *WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM* for you based on whether any views in the dialog return true from View.onCheckIsTextEditor(). Generally you want this set for a Dialog without text editors, so that it will be placed on top of the current input method UI. You can modify this behavior by forcing the flag to your desired mode after calling onCreate.

I had the problem you've mentioned with EditText in ListView inside a Dialog. I fixed it by overwriting the custom view class (in my case ListView) with my own FocusableListView, with just one method overwritten:

public class FocusableListView extends ListView {

    public FocusableListView(Context context) {
        super(context);
    }

    public FocusableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusableListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onCheckIsTextEditor() {
        // this is where the magic happens
        return true;
    }
}

Then I'm using it in the layout file as:

<?xml version="1.0" encoding="UTF-8"?>
<com.myexample.wiget.FocusableListView 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:descendantFocusability="beforeDescendants"
android:layout_height="wrap_content" />

You can overwrite the RelativeLayout in your case the same way and it should work.


working perfect, but Android Studio(version 1.5.1) doesn't render preview layout
A
André Luiz Reis

This is what worked for me. Create the AlertDialog.Builder, set title, positiveButton, negativeButton. After do this:

    AlertDialog dialog = builder.create();
    dialog.getWindow().clearFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
    dialog.show();
    editText.requestFocus();

You don't need to use builder.show();.


Thanks André, you're the man. I tried so many solutions here on SO. This is the only one that is working
Perfect Solution!!
i
iLya2IK

The code above is very helpfull. But you must call the "show" method after the "create" method (I don't know why, but only this works in my dialog with EditText in ListView). In method onCreateDialog:

@Override
protected Dialog onCreateDialog(int id) {
  switch (id) {
    case YOUR_DIALOG_ID: {
        //...
        AlertDialog a = new AlertDialog.Builder(this)./*
        ... set the properties here
        */
        .create();
        a.show(); //!!! this is very important to call the "show" method
        a.getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        return a;
    }
  //...
  }
  return null;
}

Does that code actually work? a is initialized as an AlertDialog but the constructor is a builder. Builders have a create method which returns a dialog, dialogs have a show method to show them.
@Paul Excuse me. The code was realy wrong in the part of a dialog creation by a builder. I corrected it.
f
farid_z

Thank you! I have an embedded TextEdit in the last row of ListView embedded in the alert dialog fragment. I used your solution of clearing the flags as a post runnable and now it works perfectly.

    @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setTitle("My Title");
    m_adapter = new MyAdapter(getContext());
    builder.setAdapter(m_adapter, new OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            // TODO Auto-generated method stub

        }
    }); 

    final AlertDialog dialog = builder.create();
    final ListView listView = dialog.getListView();
    listView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {

        }
    });

    listView.post(new Runnable() {

        @Override
        public void run() {
            dialog.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);              
        }
    });
    return dialog;
}

a
android developer

Here's one way to do it:

    final Window dialogWindow = dialog.getWindow();
    dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

C
Community

I would like to add on to Paul's answer and Alexander's comment.

I myself have a dialog that's created in the onCreateDialog() method, which (seems to) require returning dialog.show();, wherefore you can not add the layoutparams to the dialog where the dialog is created. To work around this, just keep your onCreateDialog() method the same, and add an onResume() method as follows:

@Override
public void onResume() {
    super.onResume();
    Dialog dialog = getDialog();
    dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}

This should do the trick, it works for me, thankfully. Have been on this case for quite some while.


b
biegleux

full code for showing the keyboard in dialog:

public void onFocusChange(View v, boolean hasFocus) {
    Log.v("onFocusChange", hasFocus + " " + showkeyboard);
    if (hasFocus) {
        if (showkeyboard++ == 0) {
            alertDialog.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
            alertDialog.getWindow().setSoftInputMode(
                    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        } else {
            showkeyboard = 1;
        }
    }
}

trying to explain your answer. Don't put only code. Give specific answer and explanation on respective code...
M
Manish Sain
This worked for me ----
editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
//dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
InputMethodManager mgr = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.showSoftInput(v, InputMethodManager.SHOW_FORCED);
editText.setFocusable(true);
}
});

M
Mosayeb Masoumi

just add below codeLine:

// to show keyboard automatically while editText is in dialog dialog.getWindow().setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);