¿Cómo detecto si el teclado del software está visible en el dispositivo Android o no?


249

¿Hay alguna manera en Android de detectar si el teclado del software (también conocido como "soft") es visible en la pantalla?



1
lo que puede ser una solución para esto en ciertos casos (si está instalado un teclado de terceros) es verificar las notificaciones globales ya que cuando un teclado está abierto hay una notificación del sistema que dice "cambiar teclado" - se puede hacer con un NotificationListenerService
Prof

2
casi 8 años y todavía sin solución sólida, oh si introducen uno, que va a ser de API> 30 de todos modos así no importa ...
M.kazem Akhgary

Respuestas:



276

Esto funciona para mi. Quizás esta sea siempre la mejor manera para todas las versiones .

Sería efectivo hacer una propiedad de visibilidad del teclado y observar estos cambios retrasados ​​porque el método onGlobalLayout llama muchas veces. También es bueno verificar la rotación del dispositivo y windowSoftInputModeno lo es 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)
            }
        }
    }
});

3
Aquí hay un resumen de
Faruk Toptas

1
Ponga esto en una clase de utilidades y pase la actividad, ahora útil en toda la aplicación.
Justin

2
¿Y dónde se contentViewdeclara?
Code-Apprentice

1
@ Code-Apprentice En la actividad / fragmento que busca responder a los cambios del teclado virtual. ContentView es la vista raíz del diseño de esta actividad / fragmento.
airowe

1
Trabajó para mí en Android 6 y 7.
V.Marzo

71

prueba esto:

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

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

99
Esto no funciona para mi. La rama del teclado que se muestra se dispara incluso cuando el teclado nunca se mostró o se mostró y luego se cerró.
Peter Ajtai

30
siempre vuelve verdad.
shivang Trivedi

1
Sí, siempre vuelve cierto.
Léon Pelletier

Incorrecto. Esto siempre es cierto
Gaurav Arora

178
Es patético que falta el marco de Android y, lo que es peor, inconsistente en este sentido. Esto debería ser súper simple.
Vicky Chijwani

57

Creé una clase simple que se puede usar para esto: https://github.com/ravindu1024/android-keyboardlistener . Simplemente cópielo en su proyecto y úselo de la siguiente manera:

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

¿Dónde en el código exacto tengo que poner esto? Puse esto en una actividad, sin embargo, no detecta ninguna aparición o desaparición del teclado.
Toom

Bueno, puedes ponerlo en cualquier lugar dentro de tu actividad. Simplemente colóquelo en el método onCreate () después de la llamada setContentView () y debería recibir devoluciones de llamada. Por cierto, ¿en qué dispositivo lo estás probando?
ravindu1024

@MaulikDodia Lo comprobé y funciona bien en fragmentos. Configúrelo así: KeyboardUtils.addKeyboardToggleListener (getActivity (), this); y debería funcionar ¿En qué dispositivo lo estás probando?
ravindu1024

Estoy probando el dispositivo Moto-G3. @ Ravindu1024
Maulik Dodia

Gracias por este fragmento, tengo una pregunta: ¿es necesario este código para eliminar el oyente?
Pratik Butani

28

Muy fácil

1. Ponga la identificación en su vista raíz

rootViewes solo una vista que apunta a mi vista raíz en este 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. Inicialice su vista raíz en su Actividad:

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

3. Detecta si el teclado se abre o cierra 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
Hola amigo, ¿podrías decirme de dónde viene esta magia 100? ¿Por qué no 101 o 99? Gracias
Karoly

@ Karoly, creo que esto puede ser y 1. No importa. Solo esto debe ser menor que la longitud real del teclado
Vlad

@Karoly básicamente, está comparando el tamaño de la ventana con el tamaño de la vista raíz de su actividad. La apariencia del teclado virtual no afecta el tamaño de la ventana principal. lo que aún puede reducir el valor de 100.
MR5

El número mágico depende de su diseño de la barra superior, entre otras cosas. Por lo tanto, es relativo a su aplicación. Usé 400 en uno de los míos.
Morten Holmgaard

recuerda que onGlobalLayout se llama cada cuadro, así que asegúrate de no hacer cosas pesadas allí.
Akshay Gaonkar

8

Usé esto como 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;
}
}

Luego escribió este método:

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;

}

Luego puede usar esto para probar todos los campos (EditText, AutoCompleteTextView, etc.) que pueden haber abierto un teclado virtual:

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

Además, no es una solución ideal, pero hace el trabajo.


2
Esto funciona. Si implementa como singelton, puede aplicar a todos los textos de edición sobre el cambio de foco y tener un oyente de teclado global
Rarw el

@depperm getActivity () es específico de Fragments, prueba YourActivityName.this en su lugar. Ver también: stackoverflow.com/questions/14480129/…
Christopher Hackl


6

Puede consultar esta respuesta: https://stackoverflow.com/a/24105062/3629912

A mí me funcionó siempre.

adb shell dumpsys window InputMethod | grep "mHasSurface"

Volverá verdadero, si el teclado del software es visible.


10
Esto solo es útil durante el desarrollo, no es una solución para usar en una aplicación. (Los usuarios no tendrán adb ejecutándose)
ToolmakerSteve

5

Entonces, después de mucho tiempo jugando con AccessibilityServices, ventanas insertadas, detección de altura de pantalla, etc., creo que encontré una manera de hacer esto.

Descargo de responsabilidad: utiliza un método oculto en Android, lo que significa que podría no ser coherente. Sin embargo, en mis pruebas, parece funcionar.

El método es InputMethodManager # getInputMethodWindowVisibleHeight () , y existe desde Lollipop (5.0).

Llamada que devuelve la altura, en píxeles, del teclado actual. En teoría, un teclado no debería tener 0 píxeles de altura, así que hice una simple verificación de altura (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
}

Uso Android Hidden API para evitar la reflexión cuando llamo a métodos ocultos (lo hago mucho para las aplicaciones que desarrollo, que en su mayoría son aplicaciones hacky / tuner), pero esto también debería ser posible con la reflexión:

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

Increíble uso de reflejos
kaustubhpatange

4

Esto fue mucho menos complicado para los requisitos que necesitaba. Espero que esto pueda ayudar:

En la actividad principal:

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

El valor booleano primitivo predeterminado para mKeyboardStatus se inicializará en falso .

Luego verifique el valor de la siguiente manera y realice una acción si es necesario:

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

4

Esto debería funcionar si necesita verificar el estado del teclado:

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

Donde UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP= 100 y dip () es una función anko que convierte dpToPx:

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

3

Hice esto configurando un GlobalLayoutListener, de la siguiente manera:

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

Esto se llamará MUY a menudo
Denis Kniazhev

¿En qué casos será diferente a la respuesta de @BrownsooHan? Estoy buscando una forma en que se muestre una aplicación que dibuja sobre otras aplicaciones para apartarse del teclado.
Evan Langlois

Su respuesta es fundamentalmente la misma que la mía, solo que la mía muchos meses antes que la suya, y él tiene más votos a favor.
PearsonArtPhoto

3

Pruebe este código que realmente funciona si KeyboardShown se muestra, entonces esta función devuelve un valor verdadero ...

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 sigue llamándose a sí mismo cuando no se muestra.
Mandeep Singh

2

En mi caso, solo tenía uno EditTextpara administrar en mi diseño, así que encontré esta solución. Funciona bien, básicamente es una costumbre EditTextque escucha el foco y envía una transmisión local si el foco cambia o si se presiona el botón Atrás / Listo. Para trabajar, debe colocar un ficticio Viewen su diseño con android:focusable="true"y android:focusableInTouchMode="true"porque cuando llame clearFocus()al foco se reasignará a la primera vista enfocable. Ejemplo de vista ficticia:

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

Informaciones adicionales

La solución que detecta la diferencia en los cambios de diseño no funciona muy bien porque depende en gran medida de la densidad de la pantalla, ya que 100 px puede ser mucho en cierto dispositivo y nada en otros puede obtener falsos positivos. También diferentes proveedores tienen diferentes teclados.


1

En Android puedes detectar a través de ADB shell. Escribí y uso este método:

{
        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
¿Puedes mejorar esta respuesta con un ejemplo más concreto, con todas las importaciones y un ejemplo de trabajo?
Usuario3

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 respuesta de @iWantScala es genial, pero no funciona para mí
rootView.getRootView().getHeight()siempre tiene el mismo valor

una forma es definir dos vars

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

agregar oyente global

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

Entonces revisa

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

funciona bien


1

Finalmente, ahora hay una forma directa a partir de Android R basada en Kotlin.

 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

Tuve un problema similar. Necesitaba reaccionar al botón Enter en la pantalla (que ocultaba el teclado). En este caso, puede suscribirse a OnEditorAction de la vista de texto con la que se abrió el teclado; si tiene varios cuadros editables, suscríbase a todos ellos.

En su Actividad, usted tiene el control total del teclado, por lo que en ningún momento enfrentará el problema de si el teclado está abierto o no, si escucha todos los eventos de apertura y cierre.


No funciona para mi Solo recibo la tecla Enter en OnEditorAction.
3c71

0

Hay un método directo para descubrir esto. Y, no requiere los cambios de diseño.
Por lo tanto, también funciona en modo inmersivo a pantalla completa.
Pero, desafortunadamente, no funciona en todos los dispositivos. Por lo tanto, debe probarlo con su (s) dispositivo (s).

El truco es que intentas ocultar o mostrar el teclado virtual y capturar el resultado de ese intento.
Si funciona correctamente, entonces el teclado no se muestra ni se oculta realmente. Solo pedimos el estado.

Para mantenerse actualizado, simplemente repita esta operación, por ejemplo, cada 200 milisegundos, utilizando un controlador.

La implementación a continuación hace solo una comprobación.
Si realiza varias comprobaciones, debe habilitar todas las pruebas (_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;
        }
    }
};

¿Cómo llamarlo y dónde?
Mahdi Astanei

0

Aquí hay una solución para saber si el softkeyboard es visible.

  1. Verifique la ejecución de servicios en el sistema utilizando ActivityManager.getRunningServices (max_count_of_services);
  2. Desde las instancias de ActivityManager.RunningServiceInfo devueltas, verifique el valor clientCount para el servicio de teclado virtual .
  3. ClientCount mencionado anteriormente se incrementará cada vez que se muestre el teclado virtual. Por ejemplo, si clientCount era inicialmente 1, sería 2 cuando se muestra el teclado.
  4. Al descartar el teclado, clientCount se reduce. En este caso, se restablece a 1.

Algunos de los teclados populares tienen ciertas palabras clave en sus nombres de clase:

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

Desde ActivityManager.RunningServiceInfo, verifique los patrones anteriores en ClassNames. Además, ActivityManager.RunningServiceInfo's clientPackage = android, que indica que el teclado está vinculado al sistema.

La información mencionada anteriormente podría combinarse para una forma estricta de averiguar si el teclado virtual es visible.


0

Como sabrás, el teclado del software de Android será visible solo cuando haya un posible evento de tipeo. En otras palabras, el teclado solo es visible cuando EditText está enfocado. eso significa que puede obtener información sobre si el teclado está visible o no utilizando 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;
    }
});

Ahora puede usar la variable isKeyBoardVisible en cualquier lugar de la clase para determinar si el teclado está Abierto o No. Funciono bien para mi.

Nota: Este proceso no funciona cuando el teclado se abre mediante programación usando InputMethodManager porque eso no invoca OnFocusChangeListener.


no es realmente un truco, no funcionó en un caso de fragmentos anidados. No puedo decir sobre las actividades, ya que todavía no he probado esto.
antroid

0

Convertí la respuesta al kotlin, espero que esto ayude a los usuarios 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

Funciona con el ajuste No se utiliza ningún indicador de actividad y eventos de ciclo de vida. También 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)
    }
}

Método útil para mantener la vista siempre encima del teclado.

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

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

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

Donde 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

Hice esto de la siguiente manera, pero es relevante solo si su objetivo es cerrar / abrir el teclado.

ejemplo cercano: (comprobando si el teclado ya está cerrado, si no, cerrando)

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 pregunta estaba relacionada con descubrir si el teclado se muestra o no
Gopal Singh Sirvi,

-1

a puede estar usando:

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

}

Esto solo funcionará para el teclado de hardware, no para el de software
anthonymonori


-1

Si admite apis para AndroidR en su aplicación, puede usar el siguiente método.

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

Nota: Esto solo está disponible para AndroidR y la versión de Android a continuación debe seguir alguna otra respuesta o la actualizaré para eso.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.