处理输入法可见性

当输入焦点移入或移出可编辑文本字段时,Android 会显示或 隐藏输入(例如屏幕键盘), 适当的选择。系统还会决定您的界面和文本字段在上方的显示方式 输入方法例如,当屏幕上的垂直空间为 那么文本字段可能会填满输入法上方的所有空间。

对于大多数应用来说,这些默认行为就足够了。在某些情况下 但您可能希望更好地控制输入法的可见性 对布局的影响本课将介绍如何控制和响应 输入法可见性。

在 activity 启动时显示软键盘

尽管在 则不会显示软键盘。这种行为是适当的 因为输入文本可能不是 activity 中的主要任务。但是,如果 比如在登录屏幕中,输入文本是主要任务, 可能希望默认显示软键盘。

如需在 Activity 启动时显示输入法,请将 android:windowSoftInputMode 属性 值为 "stateVisible"<activity> 元素。例如:

<application ... >
    <activity
        android:windowSoftInputMode="stateVisible" ... >
        ...
    </activity>
   ...
</application>

指定界面的响应方式

当屏幕上显示软键盘时,这会减少空间 自定义属性由系统决定如何调整 部分,但可能不会做得很好。为了确保最佳行为 指定您希望系统如何在 剩余空间

如需在 activity 中声明您的首选处理方式,请使用 清单的 <activity> 元素中的 android:windowSoftInputMode 属性 其中设置了一个“调整”值。

例如,要确保系统将布局大小调整为 这样就能确保布局内容可供访问 需要滚动 - 使用 "adjustResize"

<application ... >
   <activity
       android:windowSoftInputMode="adjustResize" ... >
       ...
   </activity>
   ...
</application>

您可以将调整规范与初始软键盘结合使用 可见性规范:

<activity
    android:windowSoftInputMode="stateVisible|adjustResize" ... >
    ...
</activity>

如果界面包含"adjustResize" 用户可能需要在输入文本之后或过程中立即访问。对于 例如,如果您使用相对布局将按钮栏放置在 屏幕,使用 "adjustResize" 可调整布局大小,以显示按钮栏 。

按需显示软键盘

如果您想在 activity 的生命周期中通过某个方法确保 输入法是否可见,则可以使用 InputMethodManager 进行显示。

例如,以下方法接受一个 View,用户应在其中 打字、打电话 requestFocus(): 然后调用 showSoftInput() 以打开输入法:

Kotlin

fun showSoftKeyboard(view: View) {
   if (view.requestFocus()) {
       val imm = getSystemService(InputMethodManager::class.java)
       imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
   }
}

Java

public void showSoftKeyboard(View view) {
   if (view.requestFocus()) {
       InputMethodManager imm = getSystemService(InputMethodManager.class);
       imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
   }
}

可靠地显示软键盘

有些情况下(例如当 activity 启动时), 使用 InputMethodManager.showSoftInput() 显示软键盘 可能导致用户无法看到软件键盘。

使用 showSoftInput() 时,软键盘的可见性取决于 用于以下条件:

  • 视图必须已连接到软件键盘。(反过来, 需要窗口聚焦和编辑器 来请求视图焦点 View.requestFocus())。

  • 可见性还会受到 android:windowSoftInputMode 的影响 showSoftInput() 使用的属性和标记。

在某些用例中,例如当 activity 启动时,部分用例 不符合必需的条件。系统不会将该视图视为 连接到软件键盘时,会忽略 showSoftInput() 调用, 并且对用户不可见。

为确保软件键盘可靠地显示,您可以使用以下代码 替代方案:

Kotlin

editText.requestFocus()
WindowCompat.getInsetsController(window, editText)!!.show(WindowInsetsCompat.Type.ime())

Java

editText.requestFocus();
WindowCompat.getInsetsController(getWindow(), editText).show(WindowInsetsCompat.Type.ime());

Kotlin

class MyEditText : EditText() {
  ...
  override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
    if (hasWindowFocus) {
      requestFocus()
      post {
        val imm: InputMethodManager = getSystemService(InputMethodManager::class.java)
        imm.showSoftInput(this, 0)
      }
    }
  }
}

Java

public class MyEditText extends EditText {
  ...
  @Override
  public void onWindowFocusChanged(boolean hasWindowFocus) {
    if (hasWindowFocus) {
      requestFocus();
      post(() -> {
        InputMethodManager imm = getSystemService(InputMethodManager.class);
        imm.showSoftInput(this, 0);
      });
    }
  }
}

谨慎处理运行时可见性标志

在运行时切换软键盘可见性时,请注意不要将某些 标志值传递到这些方法中。例如,如果应用需要 通话时显示软键盘 Activity.onCreate()期间:View.getWindowInsetsController().show(ime()) activity 启动时,应用开发者应小心谨慎,切勿将 SOFT_INPUT_STATE_HIDDENSOFT_INPUT_STATE_ALWAYS_HIDDEN 标志 以防软键盘意外隐藏。

系统通常会自动隐藏软键盘

在大多数情况下,系统会处理隐藏软键盘的操作。这个 可以是以下任意一种:

根据以前的系统行为手动隐藏软键盘

在某些情况下,您的应用必须手动隐藏软键盘,例如 例如,在 View.OnFocusChangeListener.onFocusChange。谨慎使用这一技巧 ;关闭软键盘意外影响用户体验。

如果您的应用手动隐藏软键盘,您需要知道 以显式方式或隐式方式显示软键盘:

  • 之后被视为明确显示软键盘。showSoftInput() 的调用。

  • 反之,则认为软键盘已隐式显示在 以下任一情况:

通常,无论如何选择 hideSoftInputFromWindow() 都会隐藏软键盘 请求中包含 HIDE_IMPLICIT_ONLY 可以限定为仅关闭隐式请求的软键盘。

在软键盘顶部显示对话框或叠加视图

在某些情况下,编辑器 activity 可能需要创建一个不可修改的 对话框或叠加窗口。

您的应用具有几个选项,具体如以下部分所述。

总之,请确保正确处理软键盘的窗口标记 定位时间范围,使其满足以下预期 关于垂直(z 层)排序:

  • 无标志(正常情况):位于软键盘层之后,可以接收文本。
  • FLAG_NOT_FOCUSABLE :位于软键盘层之上,但无法接收文本。
  • FLAG_ALT_FOCUSABLE_IM :在软键盘层之上,可以聚焦,但不连接到 软键盘。还会阻止其下的所有视图连接到 软键盘。这对于显示不使用文本的应用对话框非常有用 输入层。
  • FLAG_NOT_FOCUSABLEFLAG_ALT_FOCUSABLE_IM :位于软键盘层之后,但无法接收文本。
  • FLAG_NOT_FOCUSABLEFLAG_NOT_TOUCH_MODAL :位于软键盘顶部,允许触摸事件“穿过” 切换到软键盘上。

创建对话框

使用 FLAG_ALT_FOCUSABLE_IM dialog 窗口标志,用于将对话框置于软键盘之上;以及用于 阻止软键盘获得焦点:

Kotlin

val content = TextView(this)
content.text = "Non-editable dialog on top of soft keyboard"
content.gravity = Gravity.CENTER
val builder = AlertDialog.Builder(this)
  .setTitle("Soft keyboard layering demo")
  .setView(content)
mDialog = builder.create()
mDialog!!.window!!
  .addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
mDialog!!.show()

Java

TextView content = new TextView(this);
content.setText("Non-editable dialog on top of soft keyboard");
content.setGravity(Gravity.CENTER);
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
    .setTitle("Soft keyboard layering demo")
    .setView(content);
mDialog = builder.create();
mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM);
mDialog.show();

创建叠加层视图

创建指定 TYPE_APPLICATION_OVERLAY 的叠加层视图 窗口类型和 FLAG_ALT_FOCUSABLE_IM 针对软键盘的 Activity 设置的窗口标志。

Kotlin

val params = WindowManager.LayoutParams(
  width,  /* Overlay window width */
  height,  /* Overlay window height */
  WindowManager.LayoutParams.TYPE_APPLICATION, /* Overlay window type */
  WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */
    or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,  /* Allow touch event send to soft keyboard behind the overlay */
  PixelFormat.TRANSLUCENT
)
params.title = "Overlay window"
mOverlayView!!.layoutParams = params
windowManager.addView(mOverlayView, params)

Java

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    width, /* Overlay window width */
    height, /* Overlay window height */
    TYPE_APPLICATION, /* Overlay window type */
    FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */
        | FLAG_NOT_TOUCH_MODAL, /* Allow touch event send to soft keyboard behind the overlay */
    PixelFormat.TRANSLUCENT);
params.setTitle("Overlay window");
mOverlayView.setLayoutParams(params);
getWindowManager().addView(mOverlayView, params);

在软键盘下方显示对话框或视图

您的应用可能需要创建一个对话框或窗口,其中包含 以下属性:

  • 显示在编辑器 activity 请求的软键盘下方 使其不受文本输入的影响。
  • 始终知晓软键盘边衬区大小的变化 调整对话框或窗口的布局。

在这种情况下,您的应用会提供多种选项。以下部分 介绍这些选项

创建对话框

通过同时设置 FLAG_NOT_FOCUSABLE 来创建对话框 窗口标志和 FLAG_ALT_FOCUSABLE_IM 窗口标志:

Kotlin

val content = TextView(this)
content.text = "Non-editable dialog behind soft keyboard"
content.gravity = Gravity.CENTER
val builder = AlertDialog.Builder(this)
  .setTitle("Soft keyboard layering demo")
  .setView(content)
mDialog = builder.create()
mDialog!!.window!!
  .addFlags(FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM)
mDialog!!.show()

Java

TextView content = new TextView(this);
content.setText("Non-editable dialog behind soft keyboard");
content.setGravity(Gravity.CENTER);
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
    .setTitle("Soft keyboard layering demo")
    .setView(content);

mDialog = builder.create();
mDialog.getWindow()
    .addFlags(FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
mDialog.show();

创建叠加层视图

通过同时设置 FLAG_NOT_FOCUSABLE 来创建叠加层视图 窗口标志和 FLAG_ALT_FOCUSABLE_IM 窗口标志:

Kotlin

val params = WindowManager.LayoutParams(
  width,  /* Overlay window width */
  height,  /* Overlay window height */
  WindowManager.LayoutParams.TYPE_APPLICATION,  /* Overlay window type */
  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
      or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
  PixelFormat.TRANSLUCENT
)
params.title = "Overlay window"
mOverlayView!!.layoutParams = params
windowManager.addView(mOverlayView, params)

Java

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    width, /* Overlay window width */
    height, /* Overlay window height */
    TYPE_APPLICATION, /* Overlay window type */
    FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM,
    PixelFormat.TRANSLUCENT);
params.setTitle("Overlay window");
mOverlayView.setLayoutParams(params);
getWindowManager().addView(mOverlayView, params);