89 votes

Bouton d'interception du clavier virtuel

J'ai l'activité avec plusieurs champs de saisie. Lorsque l'activité a commencé soft clavier est affiché. Une fois de retour touche de clavier se ferme et à proximité de l'activité j'ai besoin d'appuyer sur le bouton de retour une fois de plus.

Donc, la question: est-il possible d'intercepter la touche retour pour fermer le clavier virtuel et la finition de l'activité dans une simple pression sur un bouton de retour, sans créer des personnalisés InputMethodService?

P. S. je sais comment intercepter bouton retour dans les autres cas: onKeyDown() ou onBackPressed() , mais il ne fonctionne pas dans ce cas: seule seconde pression de la touche retour est intercepté.

78voto

mhradek Points 702

Oui, il est tout à fait possible d'afficher et de masquer le clavier et d'intercepter les appels à l'arrière du bouton. C'est un petit effort supplémentaire, comme il a été mentionné, il n'y a pas de moyen direct pour ce faire, dans l'API. La clé est de remplacer boolean dispatchKeyEventPreIme(KeyEvent) dans une mise en page. Ce que nous faisons est de créer notre disposition. J'ai choisi RelativeLayout depuis qu'il a été la base de mon Activité.

<?xml version="1.0" encoding="utf-8"?>
<com.michaelhradek.superapp.utilities.SearchLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.michaelhradek.superapp"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/white">

À l'intérieur de notre Activité, nous avons créé notre champs de saisie et d'appeler l' setActivity(...) fonction.

private void initInputField() {
    mInputField = (EditText) findViewById(R.id.searchInput);        

    InputMethodManager imm = 
        (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 
            InputMethodManager.HIDE_IMPLICIT_ONLY);

    mInputField.setOnEditorActionListener(new OnEditorActionListener() {

        @Override
        public boolean onEditorAction(TextView v, int actionId,
                KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                performSearch();
                return true;
            }

            return false;
        }
    });

    // Let the layout know we are going to be overriding the back button
    SearchLayout.setSearchActivity(this);
}

De toute évidence, l' initInputField() fonction définit le champ de saisie. Il permet également la touche entrée pour exécuter la fonctionnalité (dans mon cas une recherche).

@Override
public void onBackPressed() {
    // It's expensive, if running turn it off.
    DataHelper.cancelSearch();
    hideKeyboard();
    super.onBackPressed();
}

Ainsi, lorsque l' onBackPressed() est appelé au sein de notre layout, on peut alors faire ce que nous voulons comme masquer le clavier:

private void hideKeyboard() {
    InputMethodManager imm = (InputMethodManager) 
        getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mInputField.getWindowToken(), 0);
}

De toute façon, ici, c'est mon substitution de la RelativeLayout.

package com.michaelhradek.superapp.utilities;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.RelativeLayout;

/**
 * The root element in the search bar layout. This is a custom view just to 
 * override the handling of the back button.
 * 
 */
public class SearchLayout extends RelativeLayout {

    private static final String TAG = "SearchLayout";

    private static Activity mSearchActivity;;

    public SearchLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SearchLayout(Context context) {
        super(context);
    }

    public static void setSearchActivity(Activity searchActivity) {
        mSearchActivity = searchActivity;
    }

    /**
     * Overrides the handling of the back key to move back to the 
     * previous sources or dismiss the search dialog, instead of 
     * dismissing the input method.
     */
    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        Log.d(TAG, "dispatchKeyEventPreIme(" + event + ")");
        if (mSearchActivity != null && 
                    event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            KeyEvent.DispatcherState state = getKeyDispatcherState();
            if (state != null) {
                if (event.getAction() == KeyEvent.ACTION_DOWN
                        && event.getRepeatCount() == 0) {
                    state.startTracking(event, this);
                    return true;
                } else if (event.getAction() == KeyEvent.ACTION_UP
                        && !event.isCanceled() && state.isTracking(event)) {
                    mSearchActivity.onBackPressed();
                    return true;
                }
            }
        }

        return super.dispatchKeyEventPreIme(event);
    }
}

Malheureusement je ne peux pas prendre tout le crédit. Si vous cochez la Android source pour la rapidité de la SearchDialog boîte vous permettra de voir d'où vient l'idée.

13voto

cypressious Points 1696

J'ai découvert que redéfinir la méthode dispatchKeyEventPreIme de la classe Layout fonctionnait également bien. Définissez simplement votre activité principale en tant qu’attribut et lancez une méthode prédéfinie.

 public class LinearLayoutGradient extends LinearLayout {
    MainActivity a;

    public void setMainActivity(MainActivity a) {
        this.a = a;
    }

    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        if (a != null) {
            InputMethodManager imm = (InputMethodManager) a
                .getSystemService(Context.INPUT_METHOD_SERVICE);

            if (imm.isActive() && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                a.launchMethod;
            }
        }

        return super.dispatchKeyEventPreIme(event);
    }
}
 

7voto

jaseelder Points 674

J'ai eu du succès en annulant dispatchKeyEvent :

 @Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        finish();
        return true;
    }
    return super.dispatchKeyEvent(event);
}
 

Il cache le clavier et termine l'activité.

4voto

superuser Points 161

Comment montrez-vous le clavier logiciel?

Si vous utilisez InputMethodManager.showSoftInput() , vous pouvez essayer de passer à ResultReceiver et de mettre en œuvre onReceiveResult() pour gérer RESULT_HIDDEN

http://developer.android.com/reference/android/view/inputmethod/InputMethodManager.html

2voto

Mannaz Points 6351

J'ai eu le même problème, mais je l'ai contourné en interceptant la touche Retour. Dans mon cas (HTC Desire, Android 2.2, API d'application niveau 4), il ferme le clavier et termine immédiatement l'activité. Je ne sais pas pourquoi cela ne devrait pas fonctionner pour vous aussi:

 @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        onBackPressed();
        return true;
    }
    return super.onKeyUp(keyCode, event);
}

/**
 * Called when the activity has detected the user's press of the back key
 */
private void onBackPressed() {
    Log.e(TAG, "back pressed");
    finish();
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X