Chiudi / nascondi la tastiera virtuale di Android


Answers

Per aiutare a chiarire questa follia, vorrei iniziare scusandomi a nome di tutti gli utenti Android per il trattamento assolutamente ridicolo di Google della tastiera virtuale. Il motivo per cui ci sono così tante risposte, ognuna diversa, per la stessa semplice domanda è perché questa API, come molte altre in Android, è orribilmente progettata. 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() . Fine. Grazie mille. Ma Android ha un problema. È necessario utilizzare InputMethodManager per nascondere la tastiera. OK, bene, questa è l'API di Android per la tastiera. MA! È necessario disporre di un Context per poter accedere all'IMM. Ora abbiamo un problema Potrei voler nascondere la tastiera da una classe statica o di utilità che non ha alcun uso o necessità per qualsiasi Context . o E peggio ancora, l'IMM richiede che tu specifichi quale View (o anche peggio, quale Window ) vuoi nascondere alla tastiera FROM.

Questo è ciò che rende la tastiera così difficile da nascondere. Gentile Google: quando cerco la ricetta per una torta, non c'è RecipeProvider sulla Terra che rifiuta di fornirmi la ricetta a meno che non rispondo per prima cosa CHI la torta sarà mangiata da AND dove sarà mangiato !!

Questa triste storia si conclude con la brutta verità: per nascondere la tastiera Android, ti verrà richiesto di fornire 2 forme di identificazione: un Context e una View o una Window .

Ho creato un metodo di utilità statica che può svolgere il lavoro MOLTO solidamente, a condizione che tu lo chiami da un'attività.

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

Essere consapevoli del fatto che questo metodo di utilità funziona SOLO quando chiamato da un'attività! Il metodo precedente chiama getCurrentFocus dell'attività di destinazione per recuperare il token di finestra appropriato.

Ma supponiamo di voler nascondere la tastiera da un EditText ospitato in un DialogFragment ? Non è possibile utilizzare il metodo sopra per quello:

hideKeyboard(getActivity()); //won't work

Questo non funzionerà perché passerai un riferimento all'attività dell'ospite di Fragment , che non avrà alcun controllo focalizzato mentre il Fragment è 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 ricavate da più sprechi di tempo a inseguire questa soluzione:

Informazioni su windowSoftInputMode

C'è ancora un altro punto di discussione di cui essere a conoscenza. Per impostazione predefinita, Android assegna automaticamente il focus iniziale al primo EditText o controllo focalizzabile nella tua Activity . Ne consegue naturalmente che InputMethod (tipicamente la tastiera virtuale) risponderà all'evento di messa a fuoco mostrandosi. L'attributo windowSoftInputMode 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 incredibilmente, sembra che non faccia nulla per impedire l'apertura della tastiera quando si tocca il controllo (a meno che il focusable="false" e / o focusableInTouchMode="false" siano assegnati al controllo). Apparentemente, l'impostazione windowSoftInputMode si applica solo agli eventi di messa a fuoco automatica, non per mettere a fuoco gli eventi attivati ​​da eventi di tocco.

Pertanto, stateAlwaysHidden è MOLTO poco stateAlwaysHidden . Dovrebbe forse essere chiamato ignoreInitialFocus .

Spero che questo ti aiuti.

AGGIORNARE: Altri modi per ottenere un token finestra

Se non c'è una vista focalizzata (ad esempio può succedere se hai appena cambiato i frammenti), ci sono altre viste che forniranno un gettone finestra utile.

Queste sono alternative al codice precedente if (view == null) view = new View(activity); Questi non si riferiscono esplicitamente alla tua attività.

All'interno di una classe frammento:

view = getView().getRootView().getWindowToken();

Dato un frammento di fragment come parametro:

view = fragment.getView().getRootView().getWindowToken();

A partire dal tuo corpo contenuto:

view = findViewById(android.R.id.content).getRootView().getWindowToken();

AGGIORNAMENTO 2: Cancella messa a fuoco per evitare di mostrare nuovamente la tastiera se si apre l'app dallo sfondo

Aggiungi questa linea alla fine del metodo:

view.clearFocus();

Question

Ho un EditText e un Button nel mio layout.

Dopo aver scritto nel campo di modifica e facendo clic sul Button , voglio nascondere la tastiera virtuale. Presumo che questo è un semplice pezzo di codice, ma dove posso trovare un esempio di esso?




Just use this optimized code in your activity:

if (this.getCurrentFocus() != null) {
    InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
    inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}



Thanks to this SO answer , I derived the following which, in my case, works nicely when scrolling through the the fragments of a ViewPager...

private void hideKeyboard() {   
    // Check if no view has focus:
    View view = this.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

private void showKeyboard() {   
    // Check if no view has focus:
    View view = this.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
    }
}



Sto usando una tastiera personalizzata per inserire un numero esadecimale in modo da non far visualizzare la tastiera IMM ...

In v3.2.4_r1 setSoftInputShownOnFocus(boolean show) stato aggiunto per controllare il meteo o non per visualizzare la tastiera quando un TextView ottiene il focus, ma è ancora nascosto in modo che il riflesso debba essere usato:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    try {
        Method method = TextView.class.getMethod("setSoftInputShownOnFocus", boolean.class);
        method.invoke(mEditText, false);
    } catch (Exception e) {
        // Fallback to the second method
    }
}

Per le versioni precedenti, ho ottenuto risultati molto buoni (ma tutt'altro che perfetti) con un OnGlobalLayoutListener , aggiunto con l'aiuto di un ViewTreeObserver dalla mia vista root e quindi controllando se la tastiera è mostrata in questo modo:

@Override
public void onGlobalLayout() {
    Configuration config = getResources().getConfiguration();

    // Dont allow the default keyboard to show up
    if (config.keyboardHidden != Configuration.KEYBOARDHIDDEN_YES) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mRootView.getWindowToken(), 0);
    }
}

Quest'ultima soluzione potrebbe mostrare la tastiera per una frazione di secondo e creare problemi con le maniglie di selezione.

Quando nella tastiera viene visualizzato a schermo intero, onGlobalLayout non viene chiamato. Per evitare ciò, utilizzare TextView#setImeOptions(int) o nella dichiarazione XML di TextView:

android:imeOptions="actionNone|actionUnspecified|flagNoFullscreen|flagNoExtractUi"

Aggiornamento: trova solo le finestre di dialogo da utilizzare per non mostrare mai la tastiera e funziona in tutte le versioni:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
        WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);



Ho un'altra soluzione per nascondere la tastiera:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

Qui passa HIDE_IMPLICIT_ONLY nella posizione di showFlag e 0 nella posizione di hiddenFlag . Chiuderà forzatamente la tastiera morbida.




Ho il caso, in cui il mio EditTextpuò essere posizionato anche in un AlertDialog, quindi la tastiera dovrebbe essere chiusa al licenziamento. Il seguente codice sembra funzionare ovunque:

public static void hideKeyboard( Activity activity ) {
    InputMethodManager imm = (InputMethodManager)activity.getSystemService( Context.INPUT_METHOD_SERVICE );
    View f = activity.getCurrentFocus();
    if( null != f && null != f.getWindowToken() && EditText.class.isAssignableFrom( f.getClass() ) )
        imm.hideSoftInputFromWindow( f.getWindowToken(), 0 );
    else 
        activity.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN );
}



If you want to close the soft keyboard during a unit or functional test, you can do so by clicking the "back button" from your test:

// Close the soft keyboard from a Test
getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);

I put "back button" in quotes, since the above doesn't trigger the onBackPressed() for the Activity in question. It just closes the keyboard.

Make sure to pause for a little while before moving on, since it takes a little while to close the back button, so subsequent clicks to Views, etc., won't be registered until after a short pause (1 second is long enough ime).




For my case, I was using the a SearchView in the actionbar. After a user performs a search, the keyboard would pop open again.

Using the InputMethodManager did not close the keyboard. I had to clearFocus and set the focusable of the search view to false:

mSearchView.clearFocus();
mSearchView.setFocusable(false);



Saurabh Pareek ha la migliore risposta finora.

Potrebbe anche usare le bandiere corrette, però.

/* hide keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

/* show keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

Esempio di uso reale

/* click button */
public void onClick(View view) {      
  /* hide keyboard */
  ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
      .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

  /* start loader to check parameters ... */
}

/* loader finished */
public void onLoadFinished(Loader<Object> loader, Object data) {
    /* parameters not valid ... */

    /* show keyboard */
    ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
        .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

    /* parameters valid ... */
}



La risposta breve

Nel listener di OnClick chiama onEditorAction di EditText con IME_ACTION_DONE

button.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        someEditText.onEditorAction(EditorInfo.IME_ACTION_DONE)
    }
});

Il drill-down

Ritengo che questo metodo sia migliore, più semplice e più allineato con il modello di progettazione di Android. Nel semplice esempio sopra (e solitamente nella maggior parte dei casi comuni) avrai un EditText che ha / ha avuto il focus e di solito è stato anche quello a invocare la tastiera in primo luogo (è sicuramente in grado di invocarlo in molti scenari comuni). Allo stesso modo, dovrebbe essere quello di rilasciare la tastiera, di solito ciò può essere fatto da un ImeAction . android:imeOptions="actionDone" come funziona EditText con android:imeOptions="actionDone" , vuoi ottenere lo stesso comportamento con lo stesso metodo.

Controlla questa risposta correlata




Simple and Easy to use method, just call hideKeyboardFrom(YourActivity.this); to hide keyboard

/**
 * This method is used to hide keyboard
 * @param activity
 */
public static void hideKeyboardFrom(Activity activity) {
    InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}



Si prega di provare questo codice di seguito in oncreate ()

EditText edtView = (EditText) findViewById (R.id.editTextConvertValue); edtView.setInputType (0);




This worked for me for all the bizarre keyboard behavior

private boolean isKeyboardVisible() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    mRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = mRootView.getRootView().getHeight() - (r.bottom - r.top);
    return heightDiff > 100; // if more than 100 pixels, its probably a keyboard...
}

protected void showKeyboard() {
    if (isKeyboardVisible())
        return;
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    if (getCurrentFocus() == null) {
        inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
    } else {
        View view = getCurrentFocus();
        inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_FORCED);
    }
}

protected void hideKeyboard() {
    if (!isKeyboardVisible())
        return;
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    View view = getCurrentFocus();
    if (view == null) {
        if (inputMethodManager.isAcceptingText())
            inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
    } else {
        if (view instanceof EditText)
            ((EditText) view).setText(((EditText) view).getText().toString()); // reset edit text bug on some keyboards bug
        inputMethodManager.hideSoftInputFromInputMethod(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}



In alternativa a questa soluzione a tutto tondo , se si desidera chiudere la tastiera virtuale da qualsiasi posizione senza avere un riferimento al campo (EditText) che è stato utilizzato per aprire la tastiera, ma si è comunque voluto farlo se il campo era focalizzato, è possibile utilizzare questo (da un'attività):

if (getCurrentFocus() != null) {
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}



protected void hideSoftKeyboard(EditText input) {
    input.setInputType(0);
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(input.getWindowToken(), 0);    
}