Gerenciar a visibilidade do método de entrada

Quando o foco de entrada entra ou sai de um campo de texto editável, o Android mostra ou oculta a entrada, como o teclado na tela, conforme adequado. O sistema também decide como a interface e o campo de texto aparecem acima do método de entrada. Por exemplo, quando o espaço vertical na tela é restrito, o campo de texto pode preencher todo o espaço acima do método de entrada.

Para a maioria dos apps, esses comportamentos padrão são suficientes para atender a todas as necessidades. Em alguns casos, você pode querer mais controle sobre a visibilidade do método de entrada e como ele afeta o layout. Esta lição explica como controlar e responder à visibilidade do método de entrada.

Mostrar o teclado de software quando a atividade iniciar

Embora o Android direcione o foco para o primeiro campo de texto do layout quando a atividade é iniciada, ele não mostra o teclado de software. Esse comportamento é adequado porque a inserção de texto pode não ser a tarefa principal na atividade. No entanto, se a inserção de texto for de fato a tarefa principal, como em uma tela de login, é provável que o teclado de software apareça por padrão.

Para mostrar o método de entrada quando a atividade iniciar, adicione o atributo android:windowSoftInputMode ao elemento <activity> com o valor "stateVisible". Por exemplo:

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

Especificar como sua IU deve responder

Quando o teclado de software aparece na tela, ele reduz a quantidade de espaço disponível para a interface do app. O sistema decide como ajustar a parte visível da sua interface, mas pode não acertar. Para garantir o melhor comportamento para o app, especifique como você quer que o sistema mostre a interface no espaço restante.

Para declarar seu tratamento preferido em uma atividade, use o atributo android:windowSoftInputMode no elemento <activity> do manifesto com um dos valores de "ajuste".

Por exemplo, para garantir que o sistema redimensione o layout para o espaço disponível, o que mantém todo o conteúdo do layout acessível, mesmo que seja necessário rolar a tela, use "adjustResize":

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

É possível combinar a especificação de ajuste com a especificação de visibilidade inicial do teclado de software da seção anterior:

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

É importante especificar "adjustResize" caso a interface inclua controles que o usuário pode precisar acessar imediatamente após ou durante a realização da entrada de texto. Por exemplo, se você usa um layout relativo para colocar uma barra de botões na parte de baixo da tela, o uso de "adjustResize" redimensiona o layout para que a barra de botões apareça acima do teclado de software.

Mostrar o teclado de software sob demanda

Se houver um método no ciclo de vida da sua atividade em que você queira garantir que o método de entrada fique visível, use InputMethodManager para mostrar isso.

Por exemplo, o método a seguir usa uma View em que é esperado que o usuário digite algo, chama requestFocus() para focar e chama showSoftInput() para abrir o método de entrada:

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

Exibição confiável do teclado de software

Há determinadas situações, como quando uma atividade é iniciada, em que o uso de InputMethodManager.showSoftInput() para exibir o teclado de software pode fazer com que o teclado de software não fique visível para o usuário.

A visibilidade do teclado de software ao usar showSoftInput() depende das seguintes condições:

  • A visualização já precisa estar conectada ao teclado de software. Isso, por sua vez, exige que a janela seja focada e que a visualização do editor solicite o foco com View.requestFocus().

  • A visibilidade também pode ser afetada pelo atributo android:windowSoftInputMode e pelas sinalizações usadas pelo showSoftInput().

Em determinados casos de uso, como quando uma atividade é iniciada, algumas dessas condições obrigatórias não são atendidas. O sistema não considera a visualização como conectada ao teclado de software, ignora a chamada showSoftInput() e o teclado de software não fica visível para o usuário.

Para garantir que o teclado de software seja mostrado de forma confiável, é possível usar as seguintes alternativas:

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

Gerencie as sinalizações de visibilidade do ambiente de execução com cuidado

Ao alternar a visibilidade do teclado de software no momento da execução, tome cuidado para não transmitir determinados valores de sinalização nesses métodos. Por exemplo, se o aplicativo espera que o teclado de software seja mostrado ao chamar View.getWindowInsetsController().show(ime()) em Activity.onCreate() durante o início da atividade, os desenvolvedores precisam ter cuidado para não definir as flags SOFT_INPUT_STATE_HIDDEN ou SOFT_INPUT_STATE_ALWAYS_HIDDEN durante a inicialização inicial caso o teclado de software esteja oculto inesperadamente.

O sistema geralmente oculta o teclado de software automaticamente

Na maioria das situações, o sistema oculta o teclado de software. Pode ser qualquer um dos seguintes casos:

  • O usuário conclui a tarefa no campo de texto.
  • O usuário pressiona a tecla "Voltar" ou faz gestos de deslizar com a navegação de retorno.
  • O usuário navega para outro app, e esse outro app definiu as sinalizações SOFT_INPUT_STATE_HIDDEN ou SOFT_INPUT_STATE_ALWAYS_HIDDEN quando a visualização ganha o foco.

Ocultar o teclado de software manualmente com base no comportamento anterior do sistema

Seu app precisa ocultar o teclado de software manualmente em algumas situações, por exemplo, quando o campo de texto perde o foco em View.OnFocusChangeListener.onFocusChange. Use essa técnica com cuidado. Fechar o teclado de software prejudica a experiência do usuário.

Se o app ocultar manualmente o teclado de software, você precisará saber se ele foi exibido explicitamente ou implicitamente:

  • Considera-se que o teclado de software foi mostrado explicitamente após uma chamada para showSoftInput().

  • Por outro lado, considera-se que o teclado de software tenha sido mostrado implicitamente em uma das seguintes condições:

Normalmente, hideSoftInputFromWindow() oculta o teclado de software, independente de como foi solicitado, mas com HIDE_IMPLICIT_ONLY ele pode se limitar a dispensar apenas um teclado de software solicitado implicitamente.

Mostrar uma caixa de diálogo ou visualização de sobreposição na parte superior do teclado de software

Em algumas situações, a atividade do editor pode precisar criar uma caixa de diálogo não editável ou uma janela de sobreposição sobre o teclado de software.

Seu app tem algumas opções, que são descritas nas seções a seguir.

Em resumo, processe corretamente as flags de janela do teclado de software direcionado à janela, de modo que ela atenda às seguintes expectativas em relação à ordem vertical (z-layer):

  • Sem flags (com uso normal de maiúsculas e minúsculas): atrás da camada do teclado de software e pode receber texto.
  • FLAG_NOT_FOCUSABLE: sobre a camada do teclado de software, mas não recebe texto.
  • FLAG_ALT_FOCUSABLE_IM: na parte superior da camada do teclado de software, ela pode estar em foco, mas não está conectada ao teclado de software. Também impede que todas as visualizações abaixo dele se conectem ao teclado de software. Isso é útil para mostrar uma caixa de diálogo do app que não usa entrada de texto acima da camada do teclado de software.
  • FLAG_NOT_FOCUSABLE e FLAG_ALT_FOCUSABLE_IM: atrás da camada do teclado de software, mas não podem receber texto.
  • FLAG_NOT_FOCUSABLE e FLAG_NOT_TOUCH_MODAL : na parte de cima do teclado de software, e permita que os eventos de toque passem pela janela para o teclado de software.

Criar uma caixa de diálogo

Use a sinalização da janela de diálogo FLAG_ALT_FOCUSABLE_IM para manter a caixa de diálogo na parte superior do teclado de software e impedir que ele ganhe foco:

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

Criar uma visualização de sobreposição

Crie uma visualização de sobreposição especificando o tipo de janela TYPE_APPLICATION_OVERLAY e a flag de janela FLAG_ALT_FOCUSABLE_IM pela atividade segmentada pelo teclado de software.

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

Mostrar uma caixa de diálogo ou visualização abaixo do teclado de software

Seu app pode precisar criar uma caixa de diálogo ou janela com as seguintes propriedades:

  • Aparece abaixo do teclado de software solicitado por uma atividade do editor, de modo que não seja afetado pela entrada de texto.
  • Permanece ciente das mudanças no tamanho do encarte do teclado de software para ajustar o layout da caixa de diálogo ou da janela.

Nesse caso, o app tem várias opções. As seções a seguir descrevem essas opções.

Criar uma caixa de diálogo

Crie uma caixa de diálogo configurando as sinalizações de janela FLAG_NOT_FOCUSABLE e 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();

Criar uma visualização de sobreposição

Crie uma visualização de sobreposição configurando as sinalizações de janela FLAG_NOT_FOCUSABLE e 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);