Come posso rilevare se la tastiera del software è visibile sul dispositivo Android o no?


249

Esiste un modo in Android per rilevare se la tastiera del software (aka "soft") è visibile sullo schermo?



1
ciò che può essere una soluzione a questo in alcuni casi (se è installata una tastiera di terze parti) è controllare le notifiche globali poiché quando una tastiera è aperta c'è una notifica di sistema che dice "cambia tastiera" - può essere fatta con un NotificationListenerService
Prof

2
quasi 8 anni e ancora nessuna soluzione solida, oh se ne introducono una, sarà comunque per API> 30, quindi non importa ...
M.kazem Akhgary

Risposte:



276

Questo funziona per me. Forse questo è sempre il modo migliore per tutte le versioni .

Sarebbe efficace rendere una proprietà della visibilità della tastiera e osservare queste modifiche ritardate perché il metodo onGlobalLayout chiama molte volte. Inoltre è bene controllare la rotazione del dispositivo e windowSoftInputModenon lo è 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)
            }
        }
    }
});


1
Inseriscilo in una classe utils e passa l'attività, ora utile in tutta l'app.
Giustino,

2
E dove viene contentViewdichiarato?
Apprendista di codice il

1
@ Apprendista di codice Nell'attività / frammento stai cercando di rispondere alle modifiche della tastiera. ContentView è la vista principale del layout di questa attività / frammento.
airowe,

1
Ha funzionato per me su Android 6 e 7.
V.March

71

prova questo:

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

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

9
Questo non funziona per me. Il ramo mostrato sulla tastiera si innesca anche nel caso in cui la tastiera non sia mai stata mostrata o mostrata e quindi chiusa.
Peter Ajtai,

30
ritorna sempre vero.
Shivang Trivedi,

1
Sì, torna sempre vero.
Léon Pelletier,

Sbagliato. Questo è sempre vero
Gaurav Arora,

178
È patetico che il framework Android sia carente e, peggio ancora, incoerente al riguardo. Questo dovrebbe essere semplicissimo.
Vicky Chijwani,

57

Ho creato una classe semplice che può essere utilizzata per questo: https://github.com/ravindu1024/android-keyboardlistener . Copialo nel tuo progetto e usalo come segue:

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

Dove nel codice esatto devo inserire questo? L'ho inserito in un'attività, tuttavia, non rileva alcun aspetto o scomparsa della tastiera.
toom,

Bene, puoi metterlo ovunque all'interno della tua attività. Inseriscilo nel metodo onCreate () dopo la chiamata setContentView () e dovresti ricevere i callback. A proposito, su quale dispositivo lo stai provando?
ravindu1024,

@MaulikDodia Ho controllato e funziona bene in frammenti. Impostalo in questo modo: KeyboardUtils.addKeyboardToggleListener (getActivity (), this); e dovrebbe funzionare. Su quale dispositivo lo stai provando?
ravindu1024,

Sto provando sul dispositivo Moto-G3. @ Ravindu1024
Maulik Dodia,

Grazie per questo frammento, ho una domanda che è questo codice richiesto per rimuovere il listener?
Pratik Butani,

28

Molto facile

1. Metti l'id sulla vista di root

rootViewè solo una vista che punta alla mia vista radice in questo caso a 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. Inizializza la vista principale nella tua attività:

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

3. Rileva se la tastiera è aperta o chiusa usando 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");
                }
            }
        });

15
ehi amico, potresti dirmi da dove viene questa magia 100? Perché non 101 o 99? Grazie
Karoly,

@Karoly penso che questo potrebbe essere e 1. Non importa. Solo questo deve essere inferiore alla lunghezza reale della tastiera
Vlad

@Karoly fondamentalmente, sta confrontando le dimensioni della finestra con le dimensioni della vista radice della tua attività. l'aspetto della tastiera non influisce sulla dimensione della finestra principale. così puoi ancora abbassare il valore di 100.
mr5

Il numero magico dipende tra l'altro dal layout della barra superiore. Quindi è relativo alla tua app. Ne ho usati 400 in uno dei miei.
Morten Holmgaard,

ricorda che onGlobalLayout si chiama ogni frame, quindi assicurati di non fare cose pesanti lì dentro.
Akshay Gaonkar,

8

L'ho usato come 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;
}
}

Quindi ha scritto questo metodo:

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;

}

È quindi possibile utilizzarlo per testare tutti i campi (EditText, AutoCompleteTextView, ecc.) Che potrebbero aver aperto una tastiera virtuale:

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

Inoltre non è una soluzione ideale, ma fa il lavoro.


2
Questo funziona Se implementi come singelton puoi applicare a tutti gli edittexts sul focus focus e avere un ascoltatore di tastiera globale
Rarw

@depperm getActivity () è specifico per i frammenti, prova invece YourActivityName.this. Vedi anche: stackoverflow.com/questions/14480129/…
Christopher Hackl


6

Puoi fare riferimento a questa risposta - https://stackoverflow.com/a/24105062/3629912

Ha funzionato per me ogni volta.

adb shell dumpsys window InputMethod | grep "mHasSurface"

Restituirà vero, se la tastiera del software è visibile.


10
Ciò è utile solo durante lo sviluppo, non una soluzione da utilizzare in un'app. (Gli utenti non avranno adb in esecuzione.)
ToolmakerSteve

5

Quindi dopo molto tempo a giocare con AccessibilityServices, inserti di finestre, rilevamento dell'altezza dello schermo, ecc., Penso di aver trovato un modo per farlo.

Dichiarazione di non responsabilità: utilizza un metodo nascosto in Android, il che significa che potrebbe non essere coerente. Tuttavia, nei miei test, sembra funzionare.

Il metodo è InputMethodManager # getInputMethodWindowVisibleHeight () ed esiste da Lollipop (5.0).

Chiamata che restituisce l'altezza, in pixel, della tastiera corrente. In teoria, una tastiera non dovrebbe essere alta 0 pixel, quindi ho fatto un semplice controllo dell'altezza (in Kotlin):

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

Uso Android Hidden API per evitare la riflessione quando chiamo metodi nascosti (lo faccio molto per le app che sviluppo, che sono per lo più app hacky / tuner), ma questo dovrebbe essere possibile anche con reflection:

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

Incredibile uso delle riflessioni
kaustubhpatange

4

Questo è stato molto meno complicato per i requisiti di cui avevo bisogno. Spero che questo possa aiutare:

Sull'attività 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;
}

Il valore booleano primitivo predefinito per mKeyboardStatus verrà inizializzato su false .

Quindi controllare il valore come segue ed eseguire un'azione se necessario:

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

4

Questo dovrebbe funzionare se devi controllare lo stato della tastiera:

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

Dove UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP= 100 e dip () è una funzione anko che converte dpToPx:

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

3

Ho fatto questo impostando un GlobalLayoutListener, come segue:

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

Questo si chiamerà MOLTO spesso
Denis Kniazhev il

In quali casi sarà diverso dalla risposta di @BrownsooHan? Sto cercando un modo in cui viene mostrata un'app che disegna su altre app per allontanarsi dalla tastiera.
Evan Langlois,

La sua risposta è fondamentalmente la stessa della mia, solo io l'ho fatta molti mesi prima della sua, e ha più voti.
PearsonArtPhoto,

3

Prova questo codice funziona davvero se viene mostrato KeyboardShown, quindi questa funzione restituisce il vero valore ....

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

IsKeyboardShown continua a chiamare se stesso quando non viene visualizzato.
Mandeep Singh,

2

Nel mio caso ne avevo solo uno EditTextda gestire nel mio layout, quindi ne sono uscito con questa soluzione. Funziona bene, sostanzialmente è un'abitudine EditTextche ascolta la messa a fuoco e invia una trasmissione locale se la messa a fuoco cambia o se viene premuto il pulsante Indietro / Fine. Per funzionare è necessario posizionare un manichino Viewnel layout con android:focusable="true"e android:focusableInTouchMode="true"perché quando si chiama clearFocus()lo stato attivo verrà riassegnato alla prima vista attivabile. Esempio di vista fittizia:

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

Informazioni aggiuntive

La soluzione che rileva la differenza nelle modifiche al layout non funziona molto bene perché dipende fortemente dalla densità dello schermo, dal momento che 100px può essere molto in un determinato dispositivo e nulla in alcuni altri potresti ottenere falsi positivi. Anche diversi fornitori hanno tastiere diverse.


1

In Android è possibile rilevare tramite shell ADB. Ho scritto e utilizzo questo metodo:

{
        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
Puoi migliorare questa risposta con un esempio più concreto, con tutte le importazioni e un esempio funzionante?
Utente3

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

1

La risposta di @iWantScala è ottima ma non funziona per me
rootView.getRootView().getHeight() ha sempre lo stesso valore

un modo è definire due diversi

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

aggiungi listener globale

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

quindi controlla

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

funziona bene


1

C'è finalmente un modo diretto a partire da Android R basato su Kotlin ora.

 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 }

0

Ho avuto un problema simile. Dovevo reagire al pulsante Invio sullo schermo (che nascondeva la tastiera). In questo caso puoi iscriverti alla OnEditorAction della vista di testo con cui la tastiera era aperta - se hai più caselle modificabili, quindi iscriviti a tutte.

Nella tua attività hai il pieno controllo della tastiera, quindi non dovrai mai affrontare il problema se la tastiera è aperta o meno, se ascolti tutti gli eventi di apertura e chiusura.


Non funziona per me. Ricevo solo la chiave Invio in OnEditorAction.
3c71,

0

C'è un metodo diretto per scoprirlo. E non richiede modifiche al layout.
Quindi funziona anche in modalità fullscreen immersiva.
Ma, sfortunatamente, non funziona su tutti i dispositivi. Quindi devi provarlo con i tuoi dispositivi.

Il trucco è che si tenta di nascondere o mostrare la tastiera software e acquisire il risultato di quel tentativo.
Se funziona correttamente, la tastiera non viene mostrata o nascosta. Chiediamo solo lo stato.

Per rimanere aggiornato, è sufficiente ripetere questa operazione, ad esempio ogni 200 millisecondi, utilizzando un gestore.

L'implementazione di seguito esegue un solo controllo.
Se si eseguono più controlli, è necessario abilitare tutti i test (_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;
        }
    }
};

come chiamarlo e dove?
Mahdi Astanei,

0

Ecco una soluzione alternativa per sapere se il softkeyboard è visibile.

  1. Verificare la presenza di servizi in esecuzione sul sistema utilizzando ActivityManager.getRunningServices (max_count_of_services);
  2. Dalle istanze ActivityManager.RunningServiceInfo restituite, controllare clientCount valore per il servizio di tastiera .
  3. Il summenzionato clientCount verrà incrementato ogni volta che viene visualizzata la tastiera software. Ad esempio, se clientCount era inizialmente 1, sarebbe 2 quando viene mostrata la tastiera.
  4. Al licenziamento della tastiera, clientCount viene diminuito. In questo caso, reimposta su 1.

Alcune delle tastiere più diffuse hanno determinate parole chiave nei loro nomi di classe:

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

Da ActivityManager.RunningServiceInfo, controllare i modelli sopra in ClassNames. Inoltre, clientPackage = android di ActivityManager.RunningServiceInfo , che indica che la tastiera è collegata al sistema.

Le informazioni di cui sopra potrebbero essere combinate per un modo rigoroso di scoprire se la tastiera virtuale è visibile.


0

Come forse saprai, la tastiera del software Android sarà visibile solo quando c'è un possibile evento di digitazione. In altre parole, la tastiera diventa visibile solo quando EditText è attivo. ciò significa che è possibile ottenere il tempo in cui la tastiera è visibile o meno utilizzando 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;
    }
});

Ora puoi usare isKeyBoardVisible variabile qualsiasi punto della classe per avere tempo con la tastiera aperta o no. Ha funzionato bene nel mio caso.

Nota: questo processo non funziona quando la tastiera viene aperta a livello di codice utilizzando InputMethodManager perché non richiama OnFocusChangeListener.


non proprio un hack, non ha funzionato in un caso di frammenti nidificati. Non posso dire delle attività perché non l'ho ancora provato.
antroid

0

Ho convertito la risposta in kotlin, spero che questo aiuti per gli utenti di 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

Funziona con aggiustamento Non vengono utilizzati eventi di attività e del ciclo di vita. Anche con 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)
    }
}

Metodo utile per mantenere la vista sempre sopra la tastiera

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

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

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

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

-1

L'ho fatto come segue, ma è pertinente solo se il tuo obiettivo è chiudere / aprire il keyboad.

Chiudi esempio: (verifica se tastiera già chiusa, in caso contrario - chiusura)

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

La domanda era collegata per scoprire se la tastiera stava mostrando o no
Gopal Singh Sirvi il

-1

a potrebbe usare:

@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) {

}



-1

Se supporti le API per AndroidR nella tua app, puoi utilizzare il metodo seguente.

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

Nota: questo è disponibile solo per AndroidR e sotto la versione Android deve seguire alcune delle altre risposte o lo aggiornerò per quello.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.