Android: 对话框中的 EditText 不会弹出软键盘

因此,我遇到了一个似乎很常见的问题,即对话框中的 EditText 在获得焦点时不会显示出来。我已经看到了一些变通方法,比如在 这根线这个这个(以及更多)中,但是我从来没有看到一个令人满意的解释,说明 为什么正在发生这种情况。

我更希望 Android 使用自己的默认行为来编辑文本,而不是自己创建,但似乎每个人(在那些线程中)都已经接受了这样一个事实: 在对话框中编辑文本的默认行为是只提供一个光标而不提供键盘。为什么会这样?

郑重声明,这些变通方法似乎都不适合我——我能做到的最接近的事情是强制键盘在对话框中显示 下面(使用 InputMethodManager.toggleSoftKeyboard (*))。我的特殊配置是 API15,EditText 显示在 AlertDialog 中 ListView 的页脚中。设置了 EditText android: focus able = “ true”,onFocusChangeListener 接收焦点事件。

编辑:

按照要求,下面是我正在处理的特定代码片段。我不会为整个布局操心,但是在这个特定的应用程序中,EditText 出现是为了响应按下对话框上的一个按钮(类似于 行动观点行动观点)。它包含在一个 RelativeLayout 中,默认情况下它的可见性“消失”了:

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

构建它的代码将 relativeLayout 的可见性设置为“ Visible”(并隐藏其他 UI 元素)。根据我使用 EditText 的经验,这个 应该足以在 EditText 获得焦点时拉起键盘。然而,由于某些原因,情况并非如此。我可以设置如下 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."));
}
}
});

使用这种配置,当我 第一输入 EditText 时,onFocusChangedListener 会触发,并生成一个日志,它总是如下所示:

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

键盘出现,然后消失,可能是因为我切换了两次,但即使我确保它保持不变,它的 后面对话框窗口(在一个灰色区域) ,没有办法到达它不关闭对话框。

也就是说,我想强调的是,即使我可以得到这个解决方案的工作,我是 主要感兴趣在寻找一个简单的原因 为什么的编辑文本没有触发摆在首位,为什么这似乎是如此普遍!

52095 次浏览

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.

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.

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;
}
}
}

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;
}

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;
}

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.

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);
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);
}
});

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.

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

just add below codeLine:

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