sistema - descargar ultima version de android
¿Cómo comprobar la visibilidad del teclado del software en Android? (30)
Necesito hacer algo muy simple: averiguar si se muestra el teclado del software. ¿Es esto posible en Android?
Acabo de encontrar un error al usar la mayoría de las soluciones anteriores que sugieren agregar un número fijo.
S4 tiene un alto dpi que dio como resultado que la altura de la barra de navegación es de 100px, por lo que mi aplicación piensa que el teclado está abierto todo el tiempo.
Así que con el lanzamiento de todos los nuevos teléfonos de alta resolución, creo que usar un valor codificado no es una buena idea a largo plazo.
Un mejor enfoque que encontré después de algunas pruebas en varias pantallas y dispositivos fue usar el porcentaje.Obtenga la diferencia entre el contenido de la aplicación decorView y ur y luego verifique cuál es el porcentaje de esa diferencia. De las estadísticas que obtuve, la mayoría de la barra de navegación (independientemente del tamaño, la resolución, etc.) tomará entre el 3% y el 5% de la pantalla. Como si el teclado estuviera abierto, tomaba entre el 47% y el 55% de la pantalla.
Como conclusión, mi solución fue comprobar si la diferencia es superior al 10% y supongo que es un teclado abierto.
Algunas mejoras para evitar detectar erróneamente la visibilidad del teclado virtual en dispositivos de alta densidad:
El umbral de diferencia de altura debe definirse como 128 dp , no 128 píxeles .
Consulte el documento de diseño de Google sobre Métricas y cuadrícula , 48 dp es un tamaño cómodo para el objeto táctil y 32 dp como mínimo para los botones. El teclado virtual genérico debe incluir 4 filas de botones clave, por lo que la altura mínima del teclado debe ser: 32 dp * 4 = 128 dp , lo que significa que el tamaño del umbral debe transferirse a píxeles multiplicando la densidad del dispositivo. Para dispositivos xxxhdpi (densidad 4), el umbral de altura del teclado suave debe ser 128 * 4 = 512 píxeles.Diferencia de altura entre la vista de raíz y su área visible:
altura de la vista raíz - altura de la barra de estado - altura del marco visible = parte inferior de la vista de la raíz - parte inferior del marco visible, ya que la altura de la barra de estado es igual a la parte superior del marco visible de la vista de la raíz.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; }
Así que espero que esto ayude a alguien.
La nueva respuesta que Reuben Scratton dio es excelente y realmente eficiente, pero en realidad solo funciona si configura su windowSoftInputMode para ajustar el tamaño. Si lo configuras para ajustarPan, aún no es posible detectar si el teclado es visible usando su fragmento de código. Para solucionar esto, hice esta pequeña modificación en el código anterior.
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});
En lugar de asumir la diferencia de codificación, hice algo como esto, ya que no tenía opciones de menú en mi aplicación.
final View root= findViewById(R.id.myrootview);
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = root.getRootView().getHeight() - root.getHeight();
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
if(heightDiff <= contentViewTop){
//Soft KeyBoard Hidden
}else{
//Soft KeyBoard Shown
}
}
});
Encontré que una combinación del método de @ Reuben_Scratton junto con el método de @ Yogesh parece funcionar mejor. Combinar sus métodos produciría algo como esto:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
// ... do something here
}
}
});
Ha sido para siempre en términos de computadora, pero esta pregunta sigue siendo increíblemente relevante.
Así que tomé las respuestas anteriores y las combiné y refiné un poco ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final int DefaultKeyboardDP = 100;
// From @nathanielwolf answer... Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
// Convert the dp to pixels.
int estimatedKeyboardHeight = (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());
// Conclude whether the keyboard is shown or not.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (isShown == wasOpened) {
Log.d("Keyboard state", "Ignoring global layout change...");
return;
}
wasOpened = isShown;
listener.onVisibilityChanged(isShown);
}
});
}
Funciona para mi :)
NOTA: Si observa que DefaultKeyboardDP no se adapta a su dispositivo, juegue con el valor y publique un comentario para que todos sepan cuál debería ser el valor ... ¡finalmente obtendremos el valor correcto para todos los dispositivos!
Ha sido para siempre en términos de la computadora, pero esta pregunta sigue siendo increíblemente relevante. Así que tomé las respuestas anteriores y las combiné y refiné un poco ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isOpen = heightDiff > 100;
if (isOpen == wasOpened) {
logDebug("Ignoring global layout change...");
return;
}
wasOpened = isOpen;
listener.onVisibilityChanged(isOpen);
}
});
}
Esto funciona para mi.
La idea es que, si necesita ocultar su teclado y verificar el estado de entrada suave al mismo tiempo, use la siguiente solución:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
Este método devuelve true si se mostró el teclado antes de ocultarlo.
La verificación de la altura de los elementos no es confiable porque algunos teclados como WifiKeyboard tienen altura cero.
En su lugar, puede usar el resultado de devolución de llamada de showSoftInput () y hideSoftInput () para verificar el estado del teclado. Detalles completos y código de ejemplo en
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
Lo siento por la respuesta tardía, pero había creado una pequeña clase de ayuda para manejar eventos de apertura / cierre con notificadores a los oyentes y otras cosas útiles, puede que alguien lo encuentre útil:
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import java.util.LinkedList;
import java.util.List;
public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {
public interface SoftKeyboardStateListener {
void onSoftKeyboardOpened(int keyboardHeightInPx);
void onSoftKeyboardClosed();
}
private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
private final View activityRootView;
private int lastSoftKeyboardHeightInPx;
private boolean isSoftKeyboardOpened;
public SoftKeyboardStateWatcher(View activityRootView) {
this(activityRootView, false);
}
public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
this.activityRootView = activityRootView;
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
final Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
isSoftKeyboardOpened = true;
notifyOnSoftKeyboardOpened(heightDiff);
} else if (isSoftKeyboardOpened && heightDiff < 100) {
isSoftKeyboardOpened = false;
notifyOnSoftKeyboardClosed();
}
}
public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
}
public boolean isSoftKeyboardOpened() {
return isSoftKeyboardOpened;
}
/**
* Default value is zero {@code 0}.
*
* @return last saved keyboard height in px
*/
public int getLastSoftKeyboardHeightInPx() {
return lastSoftKeyboardHeightInPx;
}
public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.add(listener);
}
public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.remove(listener);
}
private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardOpened(keyboardHeightInPx);
}
}
}
private void notifyOnSoftKeyboardClosed() {
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardClosed();
}
}
}
}
Ejemplo de uso:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
Mi respuesta es básicamente la misma que la de Kachi, pero la envolví en una clase de ayuda agradable para limpiar la forma en que se usa en mi aplicación.
import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
* Detects Keyboard Status changes and fires events only once for each change
*/
public class KeyboardStatusDetector {
KeyboardVisibilityListener visibilityListener;
boolean keyboardVisible = false;
public void registerFragment(Fragment f) {
registerView(f.getView());
}
public void registerActivity(Activity a) {
registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
}
public KeyboardStatusDetector registerView(final View v) {
v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
v.getWindowVisibleDisplayFrame(r);
int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
/** Check this variable to debounce layout events */
if(!keyboardVisible) {
keyboardVisible = true;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
}
} else {
if(keyboardVisible) {
keyboardVisible = false;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
}
}
}
});
return this;
}
public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
visibilityListener = listener;
return this;
}
public static interface KeyboardVisibilityListener {
public void onVisibilityChanged(boolean keyboardVisible);
}
}
Puede usar esto para detectar cambios en el teclado en cualquier lugar de la aplicación de esta manera:
new KeyboardStatusDetector()
.registerFragment(fragment) //register to a fragment
.registerActivity(activity) //or register to an activity
.registerView(view) //or register to a view
.setVisibilityListener(new KeyboardVisibilityListener() {
@Override
public void onVisibilityChanged(boolean keyboardVisible) {
if(keyboardVisible) {
//Do stuff for keyboard visible
}else {
//Do stuff for keyboard hidden
}
}
});
Nota: solo use una de las llamadas "registrarse". Todos funcionan igual y solo están ahí por conveniencia.
Ninguna de estas soluciones funcionará para Lollipop como está. En Lollipop activityRootView.getRootView().getHeight()
incluye la altura de la barra de botones, mientras que medir la vista no. He adaptado la solución mejor / más simple de arriba para trabajar con Lollipop.
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
Resources res = getResources();
// The status bar is 25dp, use 50dp for assurance
float maxDiff =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());
//Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float buttonBarHeight =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
maxDiff += buttonBarHeight;
}
if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
...do something here
}
}
});
Puedes observar la ocultación de softkeyboard usando decorView de la actividad.
public final class SoftKeyboardUtil {
public static final String TAG = "SoftKeyboardUtil";
public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
final View decorView = activity.getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
int displayHight = rect.bottom - rect.top;
int hight = decorView.getHeight();
boolean hide = (double)displayHight / hight > 0.8 ;
if(Log.isLoggable(TAG, Log.DEBUG)){
Log.d(TAG ,"DecorView display hight = "+displayHight);
Log.d(TAG ,"DecorView hight = "+ hight);
Log.d(TAG, "softkeyboard visible = " + !hide);
}
listener.onSoftKeyBoardVisible(!hide);
}
});
}
public interface OnSoftKeyBoardHideListener{
void onSoftKeyBoardVisible(boolean visible);
}
}
Puedes probar esto, funciona muy bien para mí:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
También hay una solución con inserciones del sistema, pero funciona solo con API >= 21
( Android L
). Digamos que tienes BottomNavigationView
, que es hijo de LinearLayout
y necesitas ocultarlo cuando se muestra el teclado:
> LinearLayout
> ContentView
> BottomNavigationView
Todo lo que necesitas hacer es extender LinearLayout
de tal manera:
public class KeyboardAwareLinearLayout extends LinearLayout {
public KeyboardAwareLinearLayout(Context context) {
super(context);
}
public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public KeyboardAwareLinearLayout(Context context,
@Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View view = getChildAt(index);
if (view instanceof BottomNavigationView) {
int bottom = insets.getSystemWindowInsetBottom();
if (bottom >= ViewUtils.dpToPx(200)) {
// keyboard is shown
view.setVisibility(GONE);
} else {
// keyboard is hidden
view.setVisibility(VISIBLE);
}
}
}
return insets;
}
}
La idea es que cuando se muestra el teclado, las inserciones del sistema se cambian con un valor bastante grande de .bottom
.
Utilicé un poco de tiempo para resolver esto ... Corrí algunas CastExceptions, pero descubrí que puedes reemplazar tu LinearLayout en el layout.xml con el nombre de la clase.
Me gusta esto:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">
<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="@+id/rlMaster" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>
....
</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>
</LinearLayout>
De esa manera no te encontrarás con ningún problema de lanzamiento.
... y si no quieres hacer esto en todas las páginas, te recomiendo que uses "MasterPage en Android". Vea el enlace aquí: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
Utilicé una ligera variante de la respuesta de Reuban, que resultó ser más útil en ciertas circunstancias, especialmente con dispositivos de alta resolución.
final View activityRootView = findViewById(android.R.id.content);
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
}
}
});
NUEVA RESPUESTA agregada el 25 de enero de 2012
Desde que escribí la respuesta a continuación, alguien me dio un ViewTreeObserver de la existencia de ViewTreeObserver y sus amigos, API que han estado al acecho en el SDK desde la versión 1.
En lugar de requerir un tipo de diseño personalizado, una solución mucho más simple es darle a la vista raíz de su actividad una ID conocida, digamos @+id/activityRoot
, enganche un GlobalLayoutListener en ViewTreeObserver, y desde allí calcule la diferencia de tamaño entre la raíz de vista de su actividad el tamaño de la ventana:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it''s probably a keyboard...
// ... do something here
}
}
});
Usando una utilidad como:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
¡Fácil!
Nota: la aplicación debe establecer este indicador en Android Manifest android:windowSoftInputMode="adjustResize"
contrario, la solución no funcionará.
RESPUESTA ORIGINAL
Sí, es posible, pero es mucho más difícil de lo que debería ser.
Si tengo que preocuparme por cuándo aparece y desaparece el teclado (lo cual es bastante frecuente), entonces lo que hago es personalizar mi clase de diseño de nivel superior en una que onMeasure()
. La lógica básica es que si el diseño se encuentra llenando significativamente menos que el área total de la ventana, entonces es probable que se muestre un teclado virtual.
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/*
* LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when
* the soft keyboard is shown and hidden (something Android can''t tell you, weirdly).
*/
public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {
public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface Listener {
public void onSoftKeyboardShown(boolean isShowing);
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
Activity activity = (Activity)getContext();
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
int diff = (screenHeight - statusBarHeight) - height;
if (listener != null) {
listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Luego en tu clase de actividad ...
public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
mainLayout.setListener(this);
...
}
@Override
public void onSoftKeyboardShown(boolean isShowing) {
// do whatever you need to do here
}
...
}
Prueba esto:
final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
// ... do something here ... //
}
}
});
Creo que este método te ayudará a descubrir si Keybord es visible o no.
public Boolean isSoftKeyBoardVisible(){
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
Log.d(TAG,"Software Keyboard was shown");
return true;
} else {
Log.d(TAG,"Software Keyboard was not shown");
return false;
}
}
Sé cuán exacto puedes determinar si el teclado está oculto o no.
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public int getNavigationBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public boolean isKeyboardHidden() {
int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
- getSupportActionBar().getHeight();
return delta <= 0;
}
Esto funciona para tabletas. Cuando la barra de navegación se muestra horizontalmente.
Aquí está mi solución, y funciona. En lugar de buscar el tamaño de píxel, compruebe que la altura de la vista de contenido haya cambiado o no:
// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private int oldHeight;
@Override
public void onGlobalLayout() {
int newHeight = commentsContent.getMeasuredHeight();
if (newHeight < oldHeight) {
// Check for the keyboard showing in case the height difference
// is a result of orientation change
if (isSoftKeyboardShowing(CommentsActivity.this)) {
// Keyboard is showing so scroll to the latest comment
scrollToLatestComment();
}
}
oldHeight = newHeight;
}
});
public static boolean isSoftKeyboardShowing(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
return inputMethodManager.isActive();
}
Hay un método directo para descubrir esto. Y, no requiere ningún cambio de diseño.
Por lo tanto, también funciona en modo inmersivo de pantalla completa.
El truco es que intenta ocultar o mostrar el teclado suave y capturar el resultado de ese intento.
Sin pánico, esto realmente no muestra u oculta el teclado. Solo pedimos el estado.
Para mantenerse actualizado, simplemente puede repetir la operación, por ejemplo, cada 200 milisegundos, utilizando un controlador.
Puede encontrar una implementación aquí: https://.com/a/27567074/2525452
Hay un método oculto que puede ayudar para esto InputMethodManager.getInputMethodWindowVisibleHeight
,. Pero no sé por qué está escondido.
import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager
class SoftKeyboardStateWatcher(private val ctx: Context) {
companion object {
private const val DELAY = 10L
}
private val handler = Handler()
private var isSoftKeyboardOpened: Boolean = false
private val height: Int
get() {
val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
method.isAccessible = true
return method.invoke(imm) as Int
}
private val task: Runnable by lazy {
Runnable {
start()
if (!isSoftKeyboardOpened && height > 0) {
isSoftKeyboardOpened = true
notifyOnSoftKeyboardOpened(height)
} else if (isSoftKeyboardOpened && height == 0) {
isSoftKeyboardOpened = false
notifyOnSoftKeyboardClosed()
}
}
}
var listener: SoftKeyboardStateListener? = null
interface SoftKeyboardStateListener {
fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
fun onSoftKeyboardClosed()
}
fun start() {
handler.postDelayed(task, DELAY)
}
fun stop() {
handler.postDelayed({
if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
}, DELAY * 10)
}
private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
listener?.onSoftKeyboardOpened(keyboardHeightInPx)
}
private fun notifyOnSoftKeyboardClosed() {
listener?.onSoftKeyboardClosed()
}
}
La nueva respuesta de Reuben Scratton (calcular el HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) no funcionará en la actividad si establece el modo de barra de estado translúcido.
Si usa una barra de estado translúcida, activityRootView.getHeight()
nunca cambiará el clima, el teclado virtual está visible. Siempre devolverá la altura de actividad y la barra de estado.
Por ejemplo, Nexus 4, Android 5.0.1, establecido android:windowTranslucentStatus
en verdadero, devolverá 1184 para siempre, incluso los que están abiertos. Si establece android:windowTranslucentStatus
en falso, devolverá la Altura correctamente, si es invisible, devolverá 1134 (no incluye la barra de estado) 。cierre la imagen, devolverá 5xx tal vez (depende de la altura de la imagen)
No sé si este es un error. Lo intenté en 4.4.4 y 5.0.1, el resultado es el mismo.
Así que, hasta ahora, la segunda respuesta más acordada, la solución de Kachi será la forma más segura de calcular la altura de ime. Aquí hay una copia:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});
No hagas ningún código duro. La mejor manera es que tenga que cambiar el tamaño de sus vistas mientras se enfoca en EditText con KeyBord Show. Puede hacer esto agregando la propiedad de cambio de tamaño en la actividad en el archivo Manifest utilizando el siguiente código.
android:windowSoftInputMode="adjustResize"
Sé que esta es una publicación antigua, pero creo que este es el enfoque más simple que conozco y mi dispositivo de prueba es Nexus 5. No lo he probado en otros dispositivos. Espero que otros compartan su enfoque si encuentran que mi código no es bueno :)
public static boolean isKeyboardShown(Context context, View view) {
if (context == null || view == null) {
return false;
}
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
imm.hideSoftInputFromWindow devuelve booleano.
Gracias,
Tenía dificultades para mantener el estado del teclado al cambiar la orientación de los fragmentos dentro de un viewpager. No estoy seguro de por qué, pero parece que es extraño y actúa de manera diferente a una Actividad estándar.
Para mantener el estado del teclado en este caso, primero debe agregar android:windowSoftInputMode = "stateUnchanged"
a su AndroidManifest.xml
. Sin embargo, es posible que note que esto no resuelve realmente todo el problema: el teclado no se abrió para mí si se abrió antes del cambio de orientación. En todos los demás casos, el comportamiento parecía ser correcto.
Entonces, necesitamos implementar una de las soluciones mencionadas aquí. El más limpio que encontré fue el de George Maisuradze: use la devolución de llamada booleana desde hideSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
Almacené este valor en el onSaveInstanceState
método de mi Fragmento y lo recuperé onCreate
. Luego, mostré el teclado a la fuerza onCreateView
si tenía un valor de true
(devuelve verdadero si el teclado es visible antes de ocultarlo antes de la destrucción del Fragmento).
Un método que no necesita un LayoutListener
En mi caso, me gustaría guardar el estado del teclado antes de reemplazar mi Fragmento. Llamo al método hideSoftInputFromWindow from onSaveInstanceState
, que cierra el teclado y me devuelve si el teclado estaba visible o no.
Este método es sencillo pero puede cambiar el estado de su teclado.
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
La función anterior es la que uso para comprobar si un teclado está visible. Si lo es, entonces lo cierro.
A continuación se muestran los dos métodos requeridos.
Primero, defina la altura de la ventana viable en onCreate.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// add to onCreate method
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
sheight= rectgle.bottom;
//
}
Luego, agregue un método booleano que obtenga la altura de la ventana en esa instancia. Si no coincide con el original (asumiendo que no lo está cambiando en el camino ...), entonces, el teclado está abierto.
public boolean keyopen()
{
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int curheight= rectgle.bottom;
if (curheight!=sheight)
{
return true;
}
else
{
return false;
}
}
Frotz!