Menangani visibilitas metode input

Saat fokus input masuk atau keluar dari kolom teks yang dapat diedit, Android akan menampilkan atau menyembunyikan input —seperti keyboard virtual—sebagaimana sesuai. Sistem juga akan menentukan tampilan UI dan kolom teks di atas metode input. Misalnya, saat ruang vertikal di layar dibatasi, kolom teks mungkin mengisi semua ruang di atas metode input.

Di sebagian besar aplikasi, perilaku default inilah yang diperlukan. Namun, dalam beberapa kasus, Anda mungkin menginginkan kontrol lebih besar atas visibilitas metode input dan pengaruhnya terhadap tata letak. Tutorial ini menjelaskan cara mengontrol dan merespons visibilitas metode input.

Tampilkan keyboard virtual saat aktivitas dimulai

Meskipun Android memberikan fokus ke kolom teks pertama dalam tata letak Anda saat aktivitas dimulai, Android tidak akan menampilkan keyboard virtual. Perilaku ini sesuai karena memasukkan teks mungkin bukan tugas utama dalam aktivitas. Namun, jika memasukkan teks merupakan tugas utama, seperti di layar login, Anda mungkin ingin keyboard virtual muncul secara default.

Untuk menampilkan metode input saat aktivitas dimulai, tambahkan atribut android:windowSoftInputMode ke elemen <activity> dengan nilai "stateVisible". Contoh:

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

Menentukan cara UI Anda merespons

Saat muncul di layar, keyboard virtual akan mengurangi jumlah ruang yang tersedia untuk UI aplikasi Anda. Sistem memutuskan cara menyesuaikan bagian yang terlihat di UI Anda, tetapi mungkin tidak berfungsi dengan benar. Guna memastikan perilaku terbaik bagi aplikasi, tentukan cara sistem menampilkan UI di sisa ruang yang Anda inginkan.

Untuk mendeklarasikan perlakuan pilihan Anda dalam aktivitas, gunakan atribut android:windowSoftInputMode dalam elemen <activity> manifes dengan salah satu nilai "sesuaikan".

Misalnya, untuk memastikan bahwa sistem mengubah ukuran tata letak Anda ke ruang yang tersedia—yang membuat semua konten tata letak Anda tetap dapat diakses, meskipun memerlukan scroll—gunakan "adjustResize":

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

Anda dapat menggabungkan spesifikasi penyesuaian dengan spesifikasi visibilitas keyboard virtual awal dari bagian sebelumnya:

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

Penentuan "adjustResize" penting jika UI Anda menyertakan kontrol yang mungkin perlu segera diakses pengguna setelah atau saat melakukan input teks. Misalnya, jika Anda menggunakan tata letak relatif untuk menempatkan panel tombol di bagian bawah layar, penggunaan "adjustResize" akan mengubah ukuran tata letak sehingga panel tombol muncul di atas keyboard virtual.

Menampilkan keyboard virtual sesuai permintaan

Jika ada metode dalam siklus proses aktivitas di mana Anda ingin memastikan metode input terlihat, Anda dapat menggunakan InputMethodManager untuk menampilkannya.

Misalnya, metode berikut mengambil View tempat pengguna diharapkan mengetik sesuatu, memanggil requestFocus() untuk memberikan fokus, lalu memanggil showSoftInput() untuk membuka metode input:

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

Menampilkan keyboard virtual dengan andal

Ada situasi tertentu, misalnya saat suatu aktivitas dimulai, ketika menggunakan InputMethodManager.showSoftInput() untuk menampilkan keyboard virtual dapat menyebabkan keyboard virtual tidak terlihat oleh pengguna.

Visibilitas keyboard virtual saat menggunakan showSoftInput() bergantung pada kondisi berikut:

  • Tampilan tersebut harus sudah terhubung ke keyboard virtual. (Hal ini pada akhirnya mengharuskan jendela untuk difokuskan dan tampilan editor untuk meminta fokus tampilan dengan View.requestFocus()).

  • Visibilitas juga dapat dipengaruhi oleh atribut dan tanda android:windowSoftInputMode yang digunakan oleh showSoftInput().

Dalam kasus penggunaan tertentu, seperti saat suatu aktivitas dimulai, beberapa kondisi wajib ini tidak terpenuhi. Sistem tidak menganggap tampilan terhubung ke keyboard virtual, mengabaikan panggilan showSoftInput(), dan keyboard virtual tidak terlihat oleh pengguna.

Untuk memastikan keyboard virtual ditampilkan dengan akurat, Anda dapat menggunakan alternatif berikut:

  • (Direkomendasikan) Gunakan WindowInsetsControllerCompat. Objek ini menampilkan keyboard virtual selama Activity.onCreate() seperti yang ditunjukkan dalam cuplikan kode berikut. Panggilan dijamin akan dijadwalkan setelah jendela difokus.

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

Tangani tanda visibilitas runtime dengan cermat

Saat mengalihkan visibilitas keyboard virtual saat runtime, berhati-hatilah agar tidak meneruskan nilai flag tertentu ke dalam metode ini. Misalnya, jika aplikasi mengharapkan keyboard virtual muncul saat memanggil View.getWindowInsetsController().show(ime()) dalam Activity.onCreate() selama aktivitas dimulai, developer aplikasi harus berhati-hati untuk tidak menetapkan tanda SOFT_INPUT_STATE_HIDDEN atau SOFT_INPUT_STATE_ALWAYS_HIDDEN selama peluncuran awal jika keyboard virtual tersembunyi secara tidak terduga.

Sistem biasanya menyembunyikan keyboard virtual secara otomatis

Pada kebanyakan situasi, sistem menangani penyembunyian keyboard virtual. Hal ini dapat berupa salah satu kasus berikut:

  • Pengguna menyelesaikan tugas di kolom teks.
  • Pengguna menekan tombol kembali atau gestur geser dengan navigasi kembali.
  • Pengguna membuka aplikasi lain, dan aplikasi lain tersebut telah menetapkan tanda SOFT_INPUT_STATE_HIDDEN atau SOFT_INPUT_STATE_ALWAYS_HIDDEN saat tampilan mendapatkan fokus.

Menyembunyikan keyboard virtual secara manual berdasarkan perilaku sistem sebelumnya

Aplikasi Anda harus menyembunyikan keyboard virtual secara manual dalam beberapa situasi—misalnya, saat kolom teks kehilangan fokus di View.OnFocusChangeListener.onFocusChange. Gunakan teknik ini dengan bijak; menutup keyboard virtual secara tiba-tiba akan mengganggu pengalaman pengguna.

Jika aplikasi menyembunyikan keyboard virtual secara manual, Anda perlu tahu apakah keyboard virtual ditampilkan secara eksplisit atau implisit:

  • Keyboard virtual dianggap telah secara eksplisit ditampilkan setelah panggilan ke showSoftInput().

  • Sebaliknya, keyboard virtual dianggap telah ditampilkan secara implisit dalam salah satu kondisi berikut:

    • Sistem menampilkan keyboard virtual saat menerapkan android:windowSoftInputMode.
    • Aplikasi Anda meneruskan SHOW_IMPLICIT ke showSoftInput().

Biasanya, hideSoftInputFromWindow() menyembunyikan keyboard virtual terlepas dari cara permintaannya, tetapi dengan HIDE_IMPLICIT_ONLY , opsi ini dapat dibatasi untuk hanya menutup keyboard virtual yang diminta secara implisit.

Menampilkan tampilan dialog atau overlay di atas keyboard virtual

Dalam beberapa situasi, aktivitas editor mungkin perlu membuat dialog atau jendela overlay yang tidak dapat diedit di atas keyboard virtual.

Aplikasi Anda memiliki beberapa opsi, yang dijelaskan di bagian berikut.

Singkatnya, pastikan untuk menangani flag jendela dari keyboard virtual yang menargetkan jendela dengan benar sehingga memenuhi ekspektasi berikut terkait pengurutan vertikal (lapisan z):

  • Tidak ada flag (kasus normal): Di belakang lapisan keyboard virtual, dan dapat menerima teks.
  • FLAG_NOT_FOCUSABLE : Di atas lapisan keyboard virtual, tetapi tidak dapat menerima teks.
  • FLAG_ALT_FOCUSABLE_IM : Di atas lapisan keyboard virtual, dapat difokuskan, tetapi tidak terhubung ke keyboard virtual. Juga memblokir semua tampilan di bawahnya agar tidak terhubung ke keyboard virtual. Hal ini berguna untuk menampilkan dialog aplikasi yang tidak menggunakan input teks di atas lapisan keyboard virtual.
  • FLAG_NOT_FOCUSABLE dan FLAG_ALT_FOCUSABLE_IM : Di belakang lapisan keyboard virtual, tetapi tidak dapat menerima teks.
  • FLAG_NOT_FOCUSABLE dan FLAG_NOT_TOUCH_MODAL : Di atas keyboard virtual, dan memungkinkan peristiwa sentuh "melalui" jendela ke keyboard virtual.

Membuat dialog

Gunakan flag jendela dialog FLAG_ALT_FOCUSABLE_IM untuk menjaga dialog tetap berada di atas keyboard virtual, dan untuk mencegah keyboard virtual mendapatkan fokus:

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

Membuat tampilan overlay

Buat tampilan overlay yang menentukan jenis jendela TYPE_APPLICATION_OVERLAY dan flag jendela FLAG_ALT_FOCUSABLE_IM oleh aktivitas yang ditargetkan keyboard virtual.

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

Menampilkan dialog atau tampilan di bawah keyboard virtual

Aplikasi Anda mungkin perlu membuat dialog atau jendela yang memiliki properti berikut:

  • Muncul di bawah keyboard virtual yang diminta oleh aktivitas editor sehingga tidak terpengaruh oleh input teks.
  • Tetap memperhatikan perubahan pada perubahan ukuran inset keyboard virtual untuk menyesuaikan dialog atau tata letak jendela.

Dalam hal ini, aplikasi Anda memiliki beberapa opsi. Bagian berikut menjelaskan opsi tersebut.

Membuat dialog

Buat dialog dengan menetapkan flag jendela FLAG_NOT_FOCUSABLE dan flag jendela 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();

Membuat tampilan overlay

Buat tampilan overlay dengan menetapkan flag jendela FLAG_NOT_FOCUSABLE dan flag jendela 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);