Per aiutare a chiarire questa follia, vorrei iniziare chiedendo scusa a nome di tutti gli utenti Android per il trattamento assolutamente ridicolo di Google sulla tastiera soft. Il motivo per cui ci sono così tante risposte, ognuna diversa, per la stessa semplice domanda è perché questa API, come molte altre in Android, è progettata in modo orribile. Non riesco a pensare a un modo educato per dirlo.
Voglio nascondere la tastiera. Mi aspetto di fornire Android con la seguente dichiarazione: Keyboard.hide()
. La fine. Grazie mille. Ma Android ha un problema. È necessario utilizzare il InputMethodManager
per nascondere la tastiera. OK, bene, questa è l'API di Android per la tastiera. MA! Context
Per poter accedere all'IMM è necessario disporre di un simbolo. Ora abbiamo un problema. Potrei voler nascondere la tastiera da una classe statica o di utilità che non ha alcuna utilità o necessità Context
. o E peggio ancora, l'IMM richiede di specificare da che cosa View
(o anche peggio, cosa Window
) si desidera nascondere la tastiera.
Questo è ciò che rende così difficile nascondere la tastiera. Caro Google: quando cerco la ricetta di una torta, non c'è RecipeProvider
sulla Terra che si rifiuterebbe di fornirmi la ricetta a meno che io non risponda per la prima volta CHI sarà mangiata e dove verrà mangiata !!
Questa triste storia termina con la brutta verità: per nascondere la tastiera Android, ti verrà richiesto di fornire 2 forme di identificazione: Context
ae View
o a o a Window
.
Ho creato un metodo di utilità statica che può fare il lavoro MOLTO in modo solido, a condizione che tu lo chiami da un 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);
}
Tenere presente che questo metodo di utilità funziona SOLO quando viene chiamato da un Activity
! Il metodo sopra chiama getCurrentFocus
la destinazione Activity
per recuperare il token della finestra corretto.
Ma supponiamo che tu voglia nascondere la tastiera da un EditText
ospitato in un DialogFragment
? Non puoi usare il metodo sopra per quello:
hideKeyboard(getActivity()); //won't work
Questo non funzionerà perché passerai un riferimento Fragment
all'host dell'host Activity
, che non avrà alcun controllo focalizzato mentre Fragment
viene mostrato! Wow! Quindi, per nascondere la tastiera dai frammenti, ricorro al livello inferiore, più comune e più brutto:
public static void hideKeyboardFrom(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Di seguito sono riportate alcune informazioni aggiuntive raccolte da più tempo sprecato nella ricerca di questa soluzione:
Informazioni su windowSoftInputMode
C'è ancora un altro punto di contesa di cui essere consapevoli. Per impostazione predefinita, Android assegnerà automaticamente il focus iniziale al primo EditText
o focus focus nel tuo Activity
. Ne consegue naturalmente che InputMethod (in genere la tastiera virtuale) risponderà all'evento focus mostrandosi. L' windowSoftInputMode
attributo in AndroidManifest.xml
, quando impostato su stateAlwaysHidden
, indica alla tastiera di ignorare questo focus iniziale assegnato automaticamente.
<activity
android:name=".MyActivity"
android:windowSoftInputMode="stateAlwaysHidden"/>
Quasi incredibile, sembra non fare nulla per impedire l'apertura della tastiera quando si tocca il controllo (a meno che focusable="false"
e / o non focusableInTouchMode="false"
siano assegnati al controllo). Apparentemente, l'impostazione windowSoftInputMode si applica solo agli eventi di focus automatici, non agli eventi di focus attivati da eventi touch.
Pertanto, stateAlwaysHidden
è MOLTO mal chiamato davvero. Dovrebbe forse essere chiamato ignoreInitialFocus
invece.
Spero che sia di aiuto.
AGGIORNAMENTO: altri modi per ottenere un token finestra
Se non esiste una vista focalizzata (ad es. Può succedere se hai appena cambiato frammenti), ci sono altre viste che forniranno un utile token finestra.
Queste sono alternative al codice sopra if (view == null) view = new View(activity);
Non si riferiscono esplicitamente alla tua attività.
All'interno di una classe di frammenti:
view = getView().getRootView().getWindowToken();
Dato un frammento fragment
come parametro:
view = fragment.getView().getRootView().getWindowToken();
A partire dal tuo corpo di contenuti:
view = findViewById(android.R.id.content).getRootView().getWindowToken();
AGGIORNAMENTO 2: deselezionare lo stato attivo per evitare di mostrare di nuovo la tastiera se si apre l'app dallo sfondo
Aggiungi questa riga alla fine del metodo:
view.clearFocus();