web-dev-qa-db-fra.com

Comment détecter si un clavier logiciel est visible sur Android Périphérique?

Existe-t-il un moyen dans Android de détecter si le clavier du logiciel (ak.a. "soft") est visible à l'écran?

212
andreea

Il n'y a pas de moyen direct - voir http://groups.google.com/group/Android-platform/browse_thread/thread/1728f2633cc606/5e4910f0d9eb898a où Dianne Hackborn de l'équipe Android a répondu. Cependant, vous pouvez le détecter indirectement en vérifiant si la taille de la fenêtre a changé dans #onMeasure. Voir Comment vérifier la visibilité du clavier logiciel sous Android? .

64
user770428

Cela fonctionne pour moi. Peut-être que c'est toujours le meilleur moyen pour toutes les versions.

Il serait efficace de rendre une propriété de visibilité du clavier et d'observer ces changements retardés, car la méthode onGlobalLayout appelle plusieurs fois. Aussi, il est bon de vérifier la rotation de l'appareil et windowSoftInputMode n'est pas adjustNothing.

boolean isKeyboardShowing = false;
void onKeyboardVisibilityChanged(boolean opened) {
    print("keyboard " + opened);
}

// ContentView is the root view of the layout of this activity/fragment    
contentView.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {

        Rect r = new Rect();
        contentView.getWindowVisibleDisplayFrame(r);
        int screenHeight = contentView.getRootView().getHeight();

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        int keypadHeight = screenHeight - r.bottom;

        Log.d(TAG, "keypadHeight = " + keypadHeight);

        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true
                onKeyboardVisibilityChanged(true)
            }
        }
        else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false
                onKeyboardVisibilityChanged(false)
            }
        }
    }
});
245
Brownsoo Han

essaye ça:

InputMethodManager imm = (InputMethodManager) getActivity()
            .getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        writeToLog("Software Keyboard was shown");
    } else {
        writeToLog("Software Keyboard was not shown");
    }
67
IHeartAndroid

J'ai créé une classe simple qui peut être utilisée pour cela: https://github.com/ravindu1024/Android-keyboardlistener . Copiez-le simplement dans votre projet et utilisez-le comme suit:

KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
    @Override
    public void onToggleSoftKeyboard(boolean isVisible)
    {
        Log.d("keyboard", "keyboard visible: "+isVisible);
    }
});
45
ravindu1024

Très facile

1. Mettez id sur votre vue racine

rootView n'est qu'une vue pointant sur ma vue racine, dans ce cas un relative layout:

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent"
                Android:id="@+id/addresses_confirm_root_view"
                Android:background="@color/WHITE_CLR">

2. Initialisez votre vue racine dans votre activité:

RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);

3. Détectez si le clavier est ouvert ou fermé à l'aide de getViewTreeObserver()

    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();

                if (heightDiff > 100) { 
                    Log.e("MyActivity", "keyboard opened");
                } else { 
                    Log.e("MyActivity", "keyboard closed");
                }
            }
        });
22
CommonSenseCode

J'ai utilisé cela comme base: http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-Android

/**
* To capture the result of IMM hide/show soft keyboard
*/
public class IMMResult extends ResultReceiver {
     public int result = -1;
     public IMMResult() {
         super(null);
}

@Override 
public void onReceiveResult(int r, Bundle data) {
    result = r;
}

// poll result value for up to 500 milliseconds
public int getResult() {
    try {
        int sleep = 0;
        while (result == -1 && sleep < 500) {
            Thread.sleep(100);
            sleep += 100;
        }
    } catch (InterruptedException e) {
        Log.e("IMMResult", e.getMessage());
    }
    return result;
}
}

Puis écrit cette méthode:

public boolean isSoftKeyboardShown(InputMethodManager imm, View v) {

    IMMResult result = new IMMResult();
    int res;

    imm.showSoftInput(v, 0, result);

    // if keyboard doesn't change, handle the keypress
    res = result.getResult();
    if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
            res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {

        return true;
    }
    else
        return false;

}

Vous pouvez ensuite l'utiliser pour tester tous les champs (EditText, AutoCompleteTextView, etc.) ayant ouvert un clavier logiciel:

    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1))
        //close the softkeyboard
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

Ce n’est peut-être pas une solution idéale, mais le travail est fait.

6
Christopher Hackl

Vous pouvez utiliser le résultat du rappel de showSoftInput () et de hideSoftInput () pour vérifier l'état du clavier. Détails complets et exemple de code sur

http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-Android

6
Roger Keays

Vous pouvez vous référer à cette réponse - https://stackoverflow.com/a/24105062/3629912

Cela a fonctionné pour moi à chaque fois.

adb Shell dumpsys window InputMethod | grep "mHasSurface"

Il retournera vrai si le clavier logiciel est visible.

4
l'-'l

C'était beaucoup moins compliqué pour les besoins dont j'avais besoin. J'espère que cela pourrait aider:

Sur le MainActivity:

public void dismissKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
    mKeyboardStatus = false;
}

public void showKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    mKeyboardStatus = true;
}

private boolean isKeyboardActive(){
    return mKeyboardStatus;
}

La valeur booléenne primative par défaut pour mKeyboardStatus sera initialisée à false.

Puis vérifiez la valeur comme suit et effectuez une action si nécessaire:

 mSearchBox.requestFocus();
    if(!isKeyboardActive()){
        showKeyboard();
    }else{
        dismissKeyboard();
    }
3
Futureproof

Ainsi, après avoir longtemps joué avec AccessibilityServices, des incrustations de fenêtre, la détection de la hauteur de l'écran, etc., je pense avoir trouvé un moyen de le faire.

Avertissement: il utilise une méthode cachée dans Android, ce qui signifie qu'il pourrait ne pas être cohérent. Cependant, lors de mes tests, cela semble fonctionner.

La méthode est InputMethodManager # getInputMethodWindowVisibleHeight () , et existe depuis Lollipop (5.0).

L'appel qui renvoie la hauteur, en pixels, du clavier actuel. En théorie, un clavier ne devrait pas faire 0 pixels de haut, alors j'ai fait une simple vérification de la hauteur (en Kotlin):

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
    //keyboard is shown
else {
    //keyboard is hidden
}

J'utilise Android Hidden API pour éviter les réflexions lorsque j'appelle des méthodes cachées (je le fais souvent pour les applications que je développe, qui sont principalement des applications de hacky/tuner), mais cela devrait également être possible avec la réflexion :

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.Java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic
3
TheWanderer

Cela devrait fonctionner si vous devez vérifier l'état du clavier:

fun Activity.isKeyboardOpened(): Boolean {
    val r = Rect()

    val activityRoot = getActivityRoot()
    val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)

    activityRoot.getWindowVisibleDisplayFrame(r)

    val heightDiff = activityRoot.rootView.height - r.height()

    return heightDiff > visibleThreshold;
}

fun Activity.getActivityRoot(): View {
    return (findViewById<ViewGroup>(Android.R.id.content)).getChildAt(0);
}

UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP = 100 et dip () est une fonction qui convertit dpToPx:

fun dip(value: Int): Int {
    return (value * Resources.getSystem().displayMetrics.density).toInt()
}
2
Bohdan Oliynyk

Dans mon cas, je n'avais qu'un seul EditText à gérer dans ma mise en page, donc je suis arrivé avec cette solution. Cela fonctionne bien. En gros, c’est une coutume EditText qui écoute le focus et envoie une diffusion locale si le focus change ou si le bouton Précédent/Terminé est enfoncé. Pour fonctionner, vous devez placer un mannequin View dans votre mise en page avec Android:focusable="true" et Android:focusableInTouchMode="true", car lorsque vous appelez clearFocus(), le focus sera réaffecté à la première vue active. Exemple de vue factice:

<View
Android:layout_width="1dp"
Android:layout_height="1dp"
Android:focusable="true"
Android:focusableInTouchMode="true"/>

Informations supplémentaires

La solution qui détecte la différence dans les modifications d’agencement ne fonctionne pas très bien car elle dépend fortement de la densité de l’écran, car 100px peut être beaucoup dans un appareil donné et rien dans certains autres ne peut donner de faux positifs. Aussi différents vendeurs ont différents claviers.

2
TheRedFox

Essayez ce code, cela fonctionne vraiment si KeyboardShown est affiché, alors cette fonction renvoie la valeur vraie ....

private final String TAG = "TextEditor";
private TextView mTextEditor;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_editor);
    mTextEditor = (TextView) findViewById(R.id.text_editor);
    mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            isKeyboardShown(mTextEditor.getRootView());
        }
    });
}

private boolean isKeyboardShown(View rootView) {
    /* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
    final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;

    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    /* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
    int heightDiff = rootView.getBottom() - r.bottom;
    /* Threshold size: dp to pixels, multiply with display density */
    boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;

    Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
            + "root view height:" + rootView.getHeight() + ", rect:" + r);

    return isKeyboardShown;
}
2
Ravi Makvana

Je l'ai fait en définissant un GlobalLayoutListener, comme suit:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 3) {
                    //Make changes for Keyboard not visible
                } else {
                    //Make changes for keyboard visible
                }
            }
        });
2
PearsonArtPhoto
final View activityRootView = findViewById(R.id.rootlayout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            Rect r = new Rect();
            activityRootView.getWindowVisibleDisplayFrame(r);

            int screenHeight = activityRootView.getRootView().getHeight();
            Log.e("screenHeight", String.valueOf(screenHeight));
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.e("heightDiff", String.valueOf(heightDiff));
            boolean visible = heightDiff > screenHeight / 3;
            Log.e("visible", String.valueOf(visible));
            if (visible) {
                Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
            }
        }
});
1
user3068659

Dans Android, vous pouvez détecter via ADB Shell. J'ai écrit et utilise cette méthode:

{
        JSch jsch = new JSch();
        try {
            Session session = jsch.getSession("<userName>", "<IP>", 22);
            session.setPassword("<Password>");
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();

            ChannelExec channel = (ChannelExec)session.openChannel("exec");
            BufferedReader in = new BufferedReader(new    
            InputStreamReader(channel.getInputStream()));
            channel.setCommand("C:/Android/android-sdk/platform-tools/adb Shell dumpsys window 
            InputMethod | findstr \"mHasSurface\"");
            channel.connect();

            String msg = null;
            String msg2 = " mHasSurface=true";

            while ((msg = in.readLine()) != null) {
                Boolean isContain = msg.contains(msg2);
                log.info(isContain);
                if (isContain){
                    log.info("Hiding keyboard...");
                    driver.hideKeyboard();
                }
                else {
                    log.info("No need to hide keyboard.");
                }
            }

            channel.disconnect();
            session.disconnect();

        } catch (JSchException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
1
Eyal Sooliman

La réponse de @ iWantScala est géniale mais ne fonctionne pas pour moi
rootView.getRootView().getHeight() a toujours la même valeur

une façon est de définir deux vars

private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;

ajouter un auditeur global

rootView.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            currentRootViewHeight = rootView.getHeight();
            if (currentRootViewHeight > maxRootViewHeight) {
                maxRootViewHeight = currentRootViewHeight;
            }
        }
    });

puis vérifier

if (currentRootViewHeight >= maxRootViewHeight) {
    // Keyboard is hidden
} else {
    // Keyboard is shown
}

fonctionne bien

1
V. Kalyuzhnyu

J'ai converti la réponse en kotlin, en espérant que cela aidera les utilisateurs de kotlin.

private fun checkKeyboardVisibility() {
    var isKeyboardShowing = false

    binding.coordinator.viewTreeObserver.addOnGlobalLayoutListener {
        val r = Rect()
        binding.coordinator.getWindowVisibleDisplayFrame(r)
        val screenHeight = binding.coordinator.rootView.height

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        val keypadHeight = screenHeight - r.bottom


        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true

            }
        } else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false

            }
        }
    }
}
0
Emre Akcan

J'avais un problème similaire. Je devais réagir au bouton Entrée à l'écran (qui masquait le clavier). Dans ce cas, vous pouvez vous abonner à OnEditorAction de la vue texte avec laquelle le clavier a été ouvert - si vous avez plusieurs zones modifiables, abonnez-vous à toutes.

Dans votre activité, vous avez le plein contrôle du clavier. Vous ne serez donc jamais confronté au problème, que le clavier soit ouvert ou non, si vous écoutez tous les événements d'ouverture et de fermeture.

0

Comme vous le savez peut-être Android, le clavier logiciel ne sera visible que s’il ya un événement possible de saisie. En d'autres termes, le clavier n'est visible que lorsque EditText est activé. cela signifie que vous pouvez voir si le clavier est visible ou non en utilisant OnFocusChangeListener.

//Declare this Globally

public boolean isKeyBoardVisible = false;

//In OnCreate *[For Activity]*, OnCreateView *[For Fragment]*

text_send.setOnFocusChangeListener(new View.OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus)
            isKeyBoardVisible = true;
        else
            isKeyBoardVisible = false;
    }
});

Vous pouvez maintenant utiliser la variable isKeyBoardVisible n'importe où dans la classe pour que le clavier soit ouvert ou non. Ça a bien marché pour moi.

Remarque: Ce processus ne fonctionne pas lorsque le clavier est ouvert par programme à l'aide de InputMethodManager car cela n'appelle pas OnFocusChangeListener.

0
sharath bhargav

Voici une solution de contournement pour savoir si le clavier virtuel est visible.

  1. Recherchez les services en cours d'exécution sur le système à l'aide de ActivityManager.getRunningServices (max_count_of_services);
  2. Dans les instances ActivityManager.RunningServiceInfo renvoyées, vérifiez la valeur clientCount du service de clavier logiciel.
  3. Le clientCount susmentionné sera incrémenté à chaque fois, le clavier virtuel est affiché. Par exemple, si clientCount était initialement égal à 1, il serait 2 lorsque le clavier est affiché.
  4. Lors de la suppression du clavier, clientCount est décrémenté. Dans ce cas, il réinitialise à 1.

Certains des claviers populaires ont certains mots-clés dans leurs classNames:

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy = clavier
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. Smart = Clavier (SmartKeyboard)

Dans ActivityManager.RunningServiceInfo, recherchez les modèles ci-dessus dans ClassNames. En outre, ActivityManager.RunningServiceInfo clientPackage= Android, indiquant que le clavier est lié au système.

Les informations mentionnées ci-dessus peuvent être combinées pour un moyen strict de savoir si un clavier logiciel est visible.

0
Satishkumar

Il existe une méthode directe pour le découvrir. Et, cela ne nécessite pas les changements de mise en page.
Cela fonctionne donc également en mode plein écran immersif.
Mais, malheureusement, cela ne fonctionne pas sur tous les appareils. Vous devez donc le tester avec votre (vos) appareil (s).

Le truc, c’est que vous essayez de masquer ou d’afficher le clavier logiciel et de capturer le résultat de cet essai.
Si cela fonctionne correctement, le clavier n'est pas vraiment affiché ou masqué. Nous demandons juste pour l'état.

Pour rester à jour, il vous suffit de répéter cette opération, par exemple: toutes les 200 millisecondes, à l'aide d'un gestionnaire.

L’implémentation ci-dessous ne fait qu’une seule vérification.
Si vous effectuez plusieurs vérifications, vous devez activer tous les tests (_keyboardVisible).

public interface OnKeyboardShowHide
{
    void    onShowKeyboard( Object param );
    void    onHideKeyboard( Object param );
}

private static Handler      _keyboardHandler    = new Handler();
private boolean             _keyboardVisible    = false;
private OnKeyboardShowHide  _keyboardCallback;
private Object              _keyboardCallbackParam;

public void start( OnKeyboardShowHide callback, Object callbackParam )
{
    _keyboardCallback      = callback;
    _keyboardCallbackParam = callbackParam;
    //
    View view = getCurrentFocus();
    if (view != null)
    {
        InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
        imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
    }
    else // if (_keyboardVisible)
    {
        _keyboardVisible = false;
        _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
    }
}

private ResultReceiver      _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
    @Override
    protected void onReceiveResult( int resultCode, Bundle resultData )
    {
        switch (resultCode)
        {
            case InputMethodManager.RESULT_SHOWN :
            case InputMethodManager.RESULT_UNCHANGED_SHOWN :
                // if (!_keyboardVisible)
                {
                    _keyboardVisible = true;
                    _keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
                }
                break;
            case InputMethodManager.RESULT_HIDDEN :
            case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
                // if (_keyboardVisible)
                {
                    _keyboardVisible = false;
                    _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
                }
                break;
        }
    }
};
0
fies