Comment détecter si le clavier logiciel est visible sur un appareil Android ou non?

249

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

andreea
la source
1
ce qui peut être une solution à cela dans certains cas (si un clavier tiers est installé) est de vérifier les notifications globales car lorsqu'un clavier est ouvert il y a une notification système qui dit "changer de clavier" - peut être fait avec un NotificationListenerService
Prof
2
presque 8 ans et toujours pas de solution solide, oh s'ils en introduisent une, ça va être pour API> 30 de toute façon alors tant
pis
Possible doublon d' Android: Détection du clavier tactile ouvert
AbdelHady

Réponses:

276

Cela fonctionne pour moi. C'est peut-être toujours le meilleur moyen pour toutes les versions .

Il serait efficace de faire une propriété de visibilité du clavier et d'observer ces changements différés car la méthode onGlobalLayout appelle plusieurs fois. Il est également bon de vérifier la rotation de l'appareil et ce windowSoftInputModen'est pas le cas 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)
            }
        }
    }
});
Brownsoo Han
la source
3
Voici un aperçu
Faruk Toptas
1
Mettez cela dans une classe d'utils et passez à l'activité - désormais utile dans toute l'application.
Justin
2
Et où est contentViewdéclaré?
Code-Apprentice
1
@ Code-Apprentice Dans l'activité / le fragment que vous cherchez à répondre aux modifications du clavier logiciel. ContentView est la vue racine de la disposition de cette activité / fragment.
airowe
1
A travaillé pour moi sur Android 6 et 7.
V.March
71

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");
    }
IHeartAndroid
la source
9
Cela ne fonctionne pas pour moi. La branche de clavier affichée se déclenche même dans les cas où le clavier n'a jamais été affiché ou a été affiché puis fermé.
Peter Ajtai
30
cela revient toujours vrai.
shivang Trivedi
1
Ouais, ça revient toujours vrai.
Léon Pelletier
Faux. Cela revient toujours vrai
Gaurav Arora
178
Il est pathétique que le cadre Android manque, et pire encore, incohérent à cet égard. Cela devrait être super simple.
Vicky Chijwani
57

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);
    }
});
ravindu1024
la source
Où dois-je mettre cela exactement dans le code? Je mets cela dans une activité, cependant, il ne détecte aucune apparence ou disparition de clavier.
toom
Eh bien, vous pouvez le placer n'importe où dans votre activité. Mettez-le simplement dans la méthode onCreate () après l'appel setContentView () et vous devriez recevoir des rappels. Btw, sur quel appareil essayez-vous?
ravindu1024
@MaulikDodia J'ai vérifié et cela fonctionne bien en fragments. Configurez-le comme ceci: KeyboardUtils.addKeyboardToggleListener (getActivity (), this); et ça devrait marcher. Sur quel appareil l'essayez-vous?
ravindu1024
J'essaie sur un appareil Moto-G3. @ Ravindu1024
Maulik Dodia
Merci pour cet extrait, j'ai une question: ce code est-il requis pour supprimer l'auditeur?
Pratik Butani
28

Très facile

1. Mettez id sur votre vue racine

rootViewest juste une vue pointant vers ma vue racine dans ce cas 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é en utilisant 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");
                }
            }
        });
CommonSenseCode
la source
15
Hé mec, pourriez-vous me dire d'où vient cette magie 100? Pourquoi pas 101 ou 99? Merci
Karoly
@Karoly je pense que cela peut être et 1. Peu importe. Seulement cela doit être inférieur à la longueur réelle du clavier
Vlad
@ Karoly en gros, il compare la taille de la fenêtre avec la taille de la vue racine de votre activité. l'apparence du clavier logiciel n'affecte pas la taille de la fenêtre principale. vous pouvez donc toujours baisser la valeur de 100.
mr5
Le nombre magique dépend entre autres de la disposition de la barre supérieure. C'est donc relatif à votre application. J'en ai utilisé 400 dans l'un des miens.
Morten Holmgaard
rappelez-vous que onGlobalLayout est appelé à chaque image, alors assurez-vous de ne pas y faire de choses lourdes.
Akshay Gaonkar
8

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

A ensuite é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.) qui peuvent avoir 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 certes pas une solution idéale, mais elle fait le travail.

Christopher Hackl
la source
2
Cela marche. Si vous implémentez en tant que singelton, vous pouvez appliquer à tous les edittexts sur le changement de focus et avoir un écouteur de clavier global
Rarw
@depperm getActivity () est spécifique aux Fragments, essayez plutôt YourActivityName.this. Voir aussi: stackoverflow.com/questions/14480129/…
Christopher Hackl
6

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 du logiciel est visible.

ll
la source
10
Ceci n'est utile que pendant le développement - pas une solution à utiliser dans une application. (Les utilisateurs n'auront pas adb en cours d'exécution.)
ToolmakerSteve
5

Donc, après avoir longtemps joué avec AccessibilityServices, les encarts 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, dans mes tests, cela semble fonctionner.

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

Appel qui renvoie la hauteur, en pixels, du clavier actuel. En théorie, un clavier ne devrait pas mesurer 0 pixels de hauteur, j'ai donc fait une simple vérification de la hauteur (dans 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 la réflexion 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 piratage / tuner), mais cela devrait être possible avec la réflexion également:

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
Le vagabond
la source
Utilisation étonnante des réflexions
kaustubhpatange
4

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

Sur l'activité principale:

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 primitive par défaut pour mKeyboardStatus sera initialisée à false .

Vérifiez ensuite la valeur comme suit et effectuez une action si nécessaire:

 mSearchBox.requestFocus();
    if(!isKeyboardActive()){
        showKeyboard();
    }else{
        dismissKeyboard();
    }
Futureproof
la source
4

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 anko qui convertit dpToPx:

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

J'ai fait cela 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
                }
            }
        });
PearsonArtPhoto
la source
Cela s'appellera TRÈS souvent
Denis Kniazhev
Dans quels cas cela sera-t-il différent de la réponse @BrownsooHan? Je cherche un moyen qu'une application qui dessine sur d'autres applications pour écarter le clavier s'affiche.
Evan Langlois
Sa réponse est fondamentalement la même que la mienne, seulement j'ai fait la mienne plusieurs mois avant la sienne, et il a plus de votes positifs.
PearsonArtPhoto
3

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

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;
}
Ravi Makvana
la source
L'isKeyboardShown continue de s'appeler lorsqu'il n'est pas affiché.
Mandeep Singh
2

Dans mon cas, je n'avais qu'un seul EditTextà gérer dans ma mise en page, donc j'ai trouvé cette solution. Cela fonctionne bien, fondamentalement, c'est une coutume EditTextqui écoute le focus et envoie une diffusion locale si le focus change ou si le bouton retour / terminé est enfoncé. Pour travailler, vous devez placer un mannequin Viewdans votre mise en page avec android:focusable="true"et android:focusableInTouchMode="true"parce que lorsque vous appelez clearFocus()le focus sera réaffecté à la première vue focusable. Exemple de vue fictive:

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

Infos supplémentaires

La solution qui détecte la différence dans les changements de disposition ne fonctionne pas très bien car elle dépend fortement de la densité de l'écran, car 100px peut être beaucoup dans un certain appareil et rien dans certains autres, vous pourriez obtenir de faux positifs. Différents fournisseurs ont également différents claviers.

TheRedFox
la source
1

Dans Android, vous pouvez détecter via le shell ADB. J'ai écrit et utilisé 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();
        }
    }
}
Eyal Sooliman
la source
1
Pouvez-vous améliorer cette réponse avec un exemple plus concret, avec toutes les importations et un exemple fonctionnel?
User3
1
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();
            }
        }
});
user3068659
la source
1

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

une façon consiste à définir deux vars

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

ajouter un écouteur 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

Vlad
la source
1

Il existe enfin un moyen direct à partir d'Android R basé sur Kotlin maintenant.

 val imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
     //Ime is visible
     //Lets move our view by the height of the IME
     view.translationX = imeInsets.bottom }
Bharadwaj Giridhar
la source
0

J'avais un problème similaire. J'avais besoin de réagir au bouton Entrée à l'écran (qui cachait le clavier). Dans ce cas, vous pouvez vous abonner à l'action OnEditorAction de la vue texte avec laquelle le clavier était ouvert - si vous avez plusieurs boîtes modifiables, alors abonnez-vous à toutes.

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

Andras Balázs Lajtha
la source
Ça ne marche pas pour moi. Je reçois uniquement la clé Entrée dans OnEditorAction.
3c71
0

Il existe une méthode directe pour le savoir. Et, il ne nécessite pas de modifications 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 ou vos appareils.

L'astuce est que vous essayez de masquer ou d'afficher le clavier virtuel et de capturer le résultat de cet essai.
Si cela fonctionne correctement, le clavier n'est pas vraiment affiché ou caché. Nous demandons simplement 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;
        }
    }
};
fies
la source
comment l'appeler et où?
Mahdi Astanei
0

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

  1. Vérifiez l'exécution des services sur le système à l'aide de ActivityManager.getRunningServices (max_count_of_services);
  2. À partir des instances ActivityManager.RunningServiceInfo retournées, vérifiez la valeur clientCount pour le service de clavier logiciel .
  3. Le clientCount susmentionné sera incrémenté à chaque fois, le clavier virtuel s'affiche. Par exemple, si clientCount était initialement égal à 1, ce serait 2 lorsque le clavier est affiché.
  4. Lors de la fermeture du clavier, clientCount est décrémenté. Dans ce cas, il revient à 1.

Certains 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, clientPackage = android , ActivityManager.RunningServiceInfo , indiquant que le clavier est lié au système.

Les informations mentionnées ci-dessus pourraient être combinées pour une manière stricte de savoir si le clavier logiciel est visible.

Satishkumar
la source
0

Comme vous le savez peut-être, le clavier du logiciel Android ne sera visible que s'il y a un événement possible de frappe. En d'autres termes, le clavier n'est visible que lorsque EditText est focalisé. cela signifie que vous pouvez obtenir la météo du 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 obtenir la météo lorsque le clavier est ouvert ou non. Ça a bien marché pour moi.

Remarque: ce processus ne fonctionne pas lorsque le clavier est ouvert par programmation à l'aide de InputMethodManager car cela n'invoque pas OnFocusChangeListener.

sharath bhargav
la source
pas vraiment un hack, n'a pas fonctionné dans un cas de fragment imbriqué. Je ne peux pas dire sur les activités car je n'ai pas encore essayé cela.
antroïde
0

J'ai converti la réponse en kotlin, j'espère que cela aide 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

            }
        }
    }
}
Emre Akcan
la source
0

Il fonctionne avec adjustNothing, le drapeau d'activité et les événements de cycle de vie sont utilisés. Aussi avec Kotlin:

/**
 * This class uses a PopupWindow to calculate the window height when the floating keyboard is opened and closed
 *
 * @param activity The parent activity
 *  The root activity that uses this KeyboardManager
 */
class KeyboardManager(private val activity: AppCompatActivity) : PopupWindow(activity), LifecycleObserver {

    private var observerList = mutableListOf<((keyboardTop: Int) -> Unit)>()

    /** The last value of keyboardTop */
    private var keyboardTop: Int = 0

    /** The view that is used to calculate the keyboard top  */
    private val popupView: View?

    /** The parent view  */
    private var parentView: View

    var isKeyboardShown = false
        private set

    /**
     * Create transparent view which will be stretched over to the full screen
     */
    private fun createFullScreenView(): View {
        val view = LinearLayout(activity)
        view.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT)
        view.background = ColorDrawable(Color.TRANSPARENT)
        return view
    }

    init {
        this.popupView = createFullScreenView()
        contentView = popupView

        softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE or LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
        inputMethodMode = INPUT_METHOD_NEEDED

        parentView = activity.findViewById(android.R.id.content)

        width = 0
        height = LayoutParams.MATCH_PARENT

        popupView.viewTreeObserver.addOnGlobalLayoutListener {
            val rect = Rect()
            popupView.getWindowVisibleDisplayFrame(rect)

            val keyboardTop = rect.bottom
            if (this.keyboardTop != keyboardTop) {
                isKeyboardShown = keyboardTop < this.keyboardTop
                this.keyboardTop = keyboardTop
                observerList.forEach { it(keyboardTop) }
            }
        }
        activity.lifecycle.addObserver(this)
    }

    /**
     * This must be called after the onResume of the Activity or inside view.post { } .
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun start() {
        parentView.post {
            if (!isShowing && parentView.windowToken != null) {
                setBackgroundDrawable(ColorDrawable(0))
                showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
            }
        }
    }

    /**
     * This manager will not be used anymore
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun close() {
        activity.lifecycle.removeObserver(this)
        observerList.clear()
        dismiss()
    }

    /**
     * Set the keyboard top observer. The observer will be notified when the keyboard top has changed.
     * For example when the keyboard is opened or closed
     *
     * @param observer The observer to be added to this provider
     */
    fun registerKeyboardTopObserver(observer: (keyboardTop: Int) -> Unit) {
        observerList.add(observer)
    }
}

Méthode utile pour garder la vue toujours au-dessus du clavier

fun KeyboardManager.updateBottomMarginIfKeyboardShown(
        view: View,
        activity: AppCompatActivity,
        // marginBottom of view when keyboard is hide
        marginBottomHideKeyboard: Int,
        // marginBottom of view when keybouard is shown
        marginBottomShowKeyboard: Int
) {
    registerKeyboardTopObserver { bottomKeyboard ->
        val bottomView = ViewUtils.getFullViewBounds(view).bottom
        val maxHeight = ScreenUtils.getFullScreenSize(activity.windowManager).y
        // Check that view is within the window size
        if (bottomView < maxHeight) {
            if (bottomKeyboard < bottomView) {
                ViewUtils.updateMargin(view, bottomMargin = bottomView - bottomKeyboard +
                        view.marginBottom + marginBottomShowKeyboard)
            } else ViewUtils.updateMargin(view, bottomMargin = marginBottomHideKeyboard)
        }
    }
}

Où getFullViewBounds

fun getLocationOnScreen(view: View): Point {
    val location = IntArray(2)
    view.getLocationOnScreen(location)
    return Point(location[0], location[1])
}

fun getFullViewBounds(view: View): Rect {
     val location = getLocationOnScreen(view)
     return Rect(location.x, location.y, location.x + view.width,
            location.y + view.height)
 }

Où getFullScreenSize

fun getFullScreenSize(wm: WindowManager? = null) =
            getScreenSize(wm) { getRealSize(it) }

private fun getScreenSize(wm: WindowManager? = null, block: Display.(Point) -> Unit): Point {
    val windowManager = wm ?: App.INSTANCE.getSystemService(Context.WINDOW_SERVICE)
            as WindowManager
    val point = Point()
    windowManager.defaultDisplay.block(point)
    return point
}

Où updateMargin

fun updateMargin(
        view: View,
        leftMargin: Int? = null,
        topMargin: Int? = null,
        rightMargin: Int? = null,
        bottomMargin: Int? = null
) {
    val layoutParams = view.layoutParams as ViewGroup.MarginLayoutParams
    if (leftMargin != null) layoutParams.leftMargin = leftMargin
    if (topMargin != null) layoutParams.topMargin = topMargin
    if (rightMargin != null) layoutParams.rightMargin = rightMargin
    if (bottomMargin != null) layoutParams.bottomMargin = bottomMargin
    view.layoutParams = layoutParams
}
Andrey Tuzov
la source
-1

Je l'ai fait comme suit, mais sa pertinence n'est que si votre objectif est de fermer / ouvrir le clavier.

exemple de fermeture: (vérification si le clavier est déjà fermé, sinon - fermeture)

imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
                    @Override
                    protected void onReceiveResult(int resultCode, Bundle resultData) {
                        super.onReceiveResult(resultCode, resultData);
                        if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
                            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    }
                });
Itay Sued
la source
La question était liée à savoir si le clavier s'affiche ou non
Gopal Singh Sirvi
-1

un peut utiliser:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.d(
    getClass().getSimpleName(), 
    String.format("conf: %s", newConfig));

    if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
        onHardwareKeyboardChange(newConfig.hardKeyboardHidden);

        hardKeyboardHidden = newConfig.hardKeyboardHidden;
    }

    if (newConfig.keyboardHidden != keyboardHidden) {
        onKeyboardChange(newConfig.keyboardHidden);

        keyboardHidden = newConfig.hardKeyboardHidden;
    }

}

public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;

//todo
private void onKeyboardChange(int keyboardHidden) {

}

//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {

}
Milan Jurkulak
la source
Cela ne fonctionnera que pour le clavier matériel, pas pour le logiciel
anthonymonori
-1

J'ai écrit un échantillon .

Ce référentiel peut aider à détecter l'état du clavier sans supposer que "le clavier doit faire plus de X parties de l'écran"

Аксенов Владимир
la source
-1

Si vous prenez en charge les API pour AndroidR dans votre application, vous pouvez utiliser la méthode ci-dessous.

In kotlin :
    var imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
        view.translationX = imeInsets.bottom 
    }

Remarque: Ceci n'est disponible que pour AndroidR et la version Android ci-dessous doit suivre une autre réponse ou je la mettrai à jour pour cela.

Pranav Patel
la source