Untuk membantu memperjelas kegilaan ini, saya ingin memulai dengan meminta maaf atas nama semua pengguna Android atas perlakuan konyol Google terhadap keyboard lunak. Alasan ada begitu banyak jawaban, masing-masing berbeda, untuk pertanyaan sederhana yang sama adalah karena API ini, seperti banyak lainnya di Android, dirancang dengan mengerikan. Saya tidak bisa memikirkan cara yang sopan untuk menyatakannya.
Saya ingin menyembunyikan keyboard. Saya berharap untuk memberikan Android dengan pernyataan berikut: Keyboard.hide()
. Tamat. Terima kasih banyak. Tapi Android punya masalah. Anda harus menggunakan InputMethodManager
untuk menyembunyikan keyboard. OKE, baiklah, ini adalah API Android untuk keyboard. TAPI! Anda harus memiliki Context
untuk mendapatkan akses ke IMM. Sekarang kita punya masalah. Saya mungkin ingin menyembunyikan keyboard dari kelas statis atau utilitas yang tidak memiliki kegunaan atau kebutuhan apa pun Context
. atau Dan JAUH lebih buruk, IMM mengharuskan Anda menentukan apa View
(atau bahkan lebih buruk, apa Window
) yang ingin Anda sembunyikan dari keyboard.
Inilah yang membuat menyembunyikan keyboard sangat menantang. Dear Google: Ketika saya mencari resep kue, tidak ada RecipeProvider
di Bumi yang akan menolak untuk memberi saya resep kecuali saya pertama kali menjawab SIAPA kue itu akan dimakan oleh DAN di mana ia akan dimakan !!
Kisah sedih ini berakhir dengan kebenaran yang buruk: untuk menyembunyikan keyboard Android, Anda akan diminta untuk memberikan 2 bentuk identifikasi: a Context
dan salah satu View
atau a Window
.
Saya telah membuat metode utilitas statis yang dapat melakukan pekerjaan SANGAT solid, asalkan Anda menyebutnya dari sebuah Activity
.
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
//Find the currently focused view, so we can grab the correct window token from it.
View view = activity.getCurrentFocus();
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = new View(activity);
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Ketahuilah bahwa metode utilitas ini HANYA berfungsi saat dipanggil dari Activity
! Metode di atas memanggil getCurrentFocus
target Activity
untuk mengambil token jendela yang tepat.
Tapi misalkan Anda ingin menyembunyikan keyboard dari EditText
host di DialogFragment
? Anda tidak dapat menggunakan metode di atas untuk itu:
hideKeyboard(getActivity()); //won't work
Ini tidak akan berhasil karena Anda akan memberikan referensi ke Fragment
host 's Activity
, yang tidak akan memiliki kontrol terfokus saat Fragment
ditampilkan! Wow! Jadi, untuk menyembunyikan keyboard dari fragmen, saya beralih ke level yang lebih rendah, lebih umum, dan lebih jelek:
public static void hideKeyboardFrom(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Di bawah ini adalah beberapa informasi tambahan yang diperoleh dari semakin banyak waktu yang terbuang mengejar solusi ini:
Tentang windowSoftInputMode
Masih ada hal lain yang perlu diperhatikan. Secara default, Android akan secara otomatis menetapkan fokus awal ke EditText
kontrol pertama atau yang dapat fokus di Activity
. Secara alami, InputMethod (biasanya keyboard lunak) akan merespons acara fokus dengan menunjukkan dirinya. The windowSoftInputMode
atribut dalam AndroidManifest.xml
, ketika diatur ke stateAlwaysHidden
, menginstruksikan keyboard untuk mengabaikan fokus awal ini secara otomatis ditugaskan.
<activity
android:name=".MyActivity"
android:windowSoftInputMode="stateAlwaysHidden"/>
Hampir tidak dapat dipercaya, tampaknya tidak melakukan apa pun untuk mencegah keyboard membuka ketika Anda menyentuh kontrol (kecuali focusable="false"
dan / atau focusableInTouchMode="false"
ditugaskan ke kontrol). Rupanya, pengaturan windowSoftInputMode hanya berlaku untuk acara fokus otomatis, bukan untuk memfokuskan acara yang dipicu oleh acara sentuh.
Oleh karena itu, stateAlwaysHidden
memang SANGAT buruk namanya. Mungkin seharusnya disebut ignoreInitialFocus
sebaliknya.
Semoga ini membantu.
PEMBARUAN: Lebih banyak cara untuk mendapatkan token jendela
Jika tidak ada tampilan terfokus (mis. Bisa terjadi jika Anda baru saja mengubah fragmen), ada tampilan lain yang akan menyediakan token jendela yang bermanfaat.
Ini adalah alternatif untuk kode di atas. if (view == null) view = new View(activity);
Ini tidak merujuk secara eksplisit ke aktivitas Anda.
Di dalam kelas fragmen:
view = getView().getRootView().getWindowToken();
Diberikan fragmen fragment
sebagai parameter:
view = fragment.getView().getRootView().getWindowToken();
Mulai dari badan konten Anda:
view = findViewById(android.R.id.content).getRootView().getWindowToken();
UPDATE 2: Hapus fokus untuk menghindari menampilkan keyboard lagi jika Anda membuka aplikasi dari latar belakang
Tambahkan baris ini ke akhir metode:
view.clearFocus();