Android: detecta el teclado abierto

Cuando se abre el teclado suave, quiero que la vista de desplazamiento se desplace hacia abajo hasta la parte inferior.

Para esto puedo usar: fullScroll (View.FOCUS_DOWN);

Pero, ¿cómo disparo ese comando después de que se desencadena el evento de apertura del teclado suave?

Según esta publicación y esta publicación en android-developers, no parece que sea posible hacer lo que quieres. Es posible que desee volver a examinar su caso de uso para lo que está haciendo. Tal vez uno de los indicadores de softInputMode funcionará para usted.

Aquí está mi solución:

1 / Una interfaz simple

 public interface KeyboardVisibilityListener { void onKeyboardVisibilityChanged(boolean keyboardVisible); } 

2 / Un método de utilidad (colóquelo donde desee, por ejemplo, en una clase llamada KeyboardUtil )

 public static void setKeyboardVisibilityListener(Activity activity, KeyboardVisibilityListener keyboardVisibilityListener) { View contentView = activity.findViewById(android.R.id.content); contentView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { private int mPreviousHeight; @Override public void onGlobalLayout() { int newHeight = contentView.getHeight(); if (mPreviousHeight != 0) { if (mPreviousHeight > newHeight) { // Height decreased: keyboard was shown keyboardVisibilityListener.onKeyboardVisibilityChanged(true); } else if (mPreviousHeight < newHeight) { // Height increased: keyboard was hidden keyboardVisibilityListener.onKeyboardVisibilityChanged(false); } else { // No change } } mPreviousHeight = newHeight; } }); } 

3 / Use de una Actividad de esta manera (un buen lugar está en onCreate):

 KeyboardUtil.setKeyboardVisibilityListener(this, mKeyboardVisibilityListener); 

mirando la fecha, posiblemente tenga una solución para su pregunta, de lo contrario:

Aquí está la misma respuesta que hice a otra pregunta relacionada: ¿Hay alguna forma de saber si se muestra el teclado virtual?

pero copio la respuesta completa aquí para evitar enlaces muertos:

Por favor revisa los cambios de configuración para tu actividad

Esto para su AndroidManifest.xml

y esto para su clase de actividad http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged(android.content.res.Configuration)

Tendrá que @Override el método público onConfigurationChanged (android.content.res.Configuration) de su actividad para poder manejar, por ejemplo, estos valores:
hardKeyboardHidden ,
teclado ,
tecladoHidden

Para todos los valores posibles, consulte http://developer.android.com/reference/android/content/res/Configuration.html

Verás algo como esto:

 HARDKEYBOARDHIDDEN_NO HARDKEYBOARDHIDDEN_UNDEFINED HARDKEYBOARDHIDDEN_YES KEYBOARDHIDDEN_NO KEYBOARDHIDDEN_UNDEFINED KEYBOARDHIDDEN_YES KEYBOARD_12KEY KEYBOARD_NOKEYS KEYBOARD_QWERTY KEYBOARD_UNDEFINED 

También allí podrás leer algo como esto:

 public int hardKeyboardHidden A flag indicating whether the hard keyboard has been hidden. public int keyboard The kind of keyboard attached to the device. public int keyboardHidden A flag indicating whether any keyboard is available. 

ACTUALIZAR:

Aquí hay una muestra específica de lo que estoy hablando:

http://developer.android.com/guide/topics/resources/runtime-changes.html

 @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); } // Checks whether a hardware keyboard is available if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show(); } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show(); } } 

Espero que esto te ayude

La única forma en que pude solucionar esto es configurando el android de mi actividad: windowSoftInputMode = “adjustResize” y luego incorpore una “vista de detector” personalizada en el diseño para manejar un cambio de tamaño de contenedor y propagarlo como un evento personalizado (a través de un Listener) para encender / apagar el teclado suave.

La siguiente publicación describe un enfoque para implementarla: EditText no desencadena cambios cuando se presiona atrás

Esto funciona para mí

 parent.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { boolean someHasFocus = false; if(host.hasFocus()) someHasFocus = true; if(folder.hasFocus()) someHasFocus = true; if(user.hasFocus()) someHasFocus = true; if(pass.hasFocus()) someHasFocus = true; if(someHasFocus){ if(bottom>oldBottom){ // Keyboard Close viewToHide.setVisibility(View.VISIBLE); }else if(bottom 

Donde padre es el diseño principal, viewToHide es la vista que se muestra u oculta cuando se muestra el teclado, y el host, la carpeta, el usuario y el pase son los EditText de mi formulario.

Y esto en el manifiesto

 android:windowSoftInputMode="stateHidden|adjustResize" 

Espero que esto ayude

Aquí está mi solución. No necesita Android: windowSoftInputMode = “adjustResize”

 public abstract class KeyboardActivity extends Activity { public static final int MIN_KEYBOARD_SIZE = 100; private Window mRootWindow; private View mRootView; private int mKeyboardHeight = -1; private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { public int height; public void onGlobalLayout() { Rect r = new Rect(); View view = mRootWindow.getDecorView(); view.getWindowVisibleDisplayFrame(r); if (height != r.height()) { int diff = height - r.height(); height = r.height(); if (Math.abs(diff) > MIN_KEYBOARD_SIZE) { int diff = height - r.height(); if (height != 0 && Math.abs(diff) > MIN_KEYBOARD_SIZE) { mKeyboardHeight = Math.abs(diff); if (diff > 0) { onKeyboardOpen(); } else { onKeyboardClosed(); } } height = r.height(); } } }; protected abstract void onKeyboardClosed(); protected abstract void onKeyboardOpen(); /** * Should return keyboard height, if keyboard was shown at least once; * @return keyboard height or -1 */ protected int getKeyboardHeight() { return mKeyboardHeight; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRootWindow = getWindow(); mRootView = mRootWindow.getDecorView().findViewById(android.R.id.content); } @Override protected void onStart() { super.onStart(); mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); } @Override protected void onStop() { super.onStop(); mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener); } } 

Luego, amplié mi actividad de esta actividad y anulo los métodos KeyboardClosed / onKeyboardOpen.

para esto lo que solía hacer es lo mismo:

  import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; public class SoftKeyboard implements View.OnFocusChangeListener { private static final int CLEAR_FOCUS = 0; private ViewGroup layout; private int layoutBottom; private InputMethodManager im; private int[] coords; private boolean isKeyboardShow; private SoftKeyboardChangesThread softKeyboardThread; private List editTextList; private View tempView; // reference to a focused EditText public SoftKeyboard(ViewGroup layout, InputMethodManager im) { this.layout = layout; keyboardHideByDefault(); initEditTexts(layout); this.im = im; this.coords = new int[2]; this.isKeyboardShow = false; this.softKeyboardThread = new SoftKeyboardChangesThread(); this.softKeyboardThread.start(); } public void openSoftKeyboard() { if(!isKeyboardShow) { layoutBottom = getLayoutCoordinates(); im.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT); softKeyboardThread.keyboardOpened(); isKeyboardShow = true; } } public void closeSoftKeyboard() { if(isKeyboardShow) { im.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); isKeyboardShow = false; } } public void setSoftKeyboardCallback(SoftKeyboardChanged mCallback) { softKeyboardThread.setCallback(mCallback); } public void unRegisterSoftKeyboardCallback() { softKeyboardThread.stopThread(); } public interface SoftKeyboardChanged { public void onSoftKeyboardHide(); public void onSoftKeyboardShow(); } private int getLayoutCoordinates() { layout.getLocationOnScreen(coords); return coords[1] + layout.getHeight(); } private void keyboardHideByDefault() { layout.setFocusable(true); layout.setFocusableInTouchMode(true); } /* * InitEditTexts now handles EditTexts in nested views * Thanks to Francesco Verheye (verheye.francesco@gmail.com) */ private void initEditTexts(ViewGroup viewgroup) { if(editTextList == null) editTextList = new ArrayList(); int childCount = viewgroup.getChildCount(); for(int i=0; i<= childCount-1;i++) { View v = viewgroup.getChildAt(i); if(v instanceof ViewGroup) { initEditTexts((ViewGroup) v); } if(v instanceof EditText) { EditText editText = (EditText) v; editText.setOnFocusChangeListener(this); editText.setCursorVisible(true); editTextList.add(editText); } } } /* * OnFocusChange does update tempView correctly now when keyboard is still shown * Thanks to Israel Dominguez (dominguez.israel@gmail.com) */ @Override public void onFocusChange(View v, boolean hasFocus) { if(hasFocus) { tempView = v; if(!isKeyboardShow) { layoutBottom = getLayoutCoordinates(); softKeyboardThread.keyboardOpened(); isKeyboardShow = true; } } } // This handler will clear focus of selected EditText private final Handler mHandler = new Handler() { @Override public void handleMessage(Message m) { switch(m.what) { case CLEAR_FOCUS: if(tempView != null) { tempView.clearFocus(); tempView = null; } break; } } }; private class SoftKeyboardChangesThread extends Thread { private AtomicBoolean started; private SoftKeyboardChanged mCallback; public SoftKeyboardChangesThread() { started = new AtomicBoolean(true); } public void setCallback(SoftKeyboardChanged mCallback) { this.mCallback = mCallback; } @Override public void run() { while(started.get()) { // Wait until keyboard is requested to open synchronized(this) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int currentBottomLocation = getLayoutCoordinates(); // There is some lag between open soft-keyboard function and when it really appears. while(currentBottomLocation == layoutBottom && started.get()) { currentBottomLocation = getLayoutCoordinates(); } if(started.get()) mCallback.onSoftKeyboardShow(); // When keyboard is opened from EditText, initial bottom location is greater than layoutBottom // and at some moment equals layoutBottom. // That broke the previous logic, so I added this new loop to handle this. while(currentBottomLocation >= layoutBottom && started.get()) { currentBottomLocation = getLayoutCoordinates(); } // Now Keyboard is shown, keep checking layout dimensions until keyboard is gone while(currentBottomLocation != layoutBottom && started.get()) { synchronized(this) { try { wait(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } currentBottomLocation = getLayoutCoordinates(); } if(started.get()) mCallback.onSoftKeyboardHide(); // if keyboard has been opened clicking and EditText. if(isKeyboardShow && started.get()) isKeyboardShow = false; // if an EditText is focused, remove its focus (on UI thread) if(started.get()) mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget(); } } public void keyboardOpened() { synchronized(this) { notify(); } } public void stopThread() { synchronized(this) { started.set(false); notify(); } } } } 

y en tu Activity o fragment llama a este método en onCreate()

  private void hideAndShowKeyBOrd() { InputMethodManager im = (InputMethodManager) getActivity().getSystemService(Service.INPUT_METHOD_SERVICE); /* Instantiate and pass a callback */ SoftKeyboard softKeyboard; softKeyboard = new SoftKeyboard(mainLayout, im); softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged() { @Override public void onSoftKeyboardHide() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { } }); } @Override public void onSoftKeyboardShow() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (viewV.getVisibility() == View.VISIBLE) { viewV.setVisibility(View.GONE); } } }); } }); } 

disfruta tu código 🙂

La respuesta de @ BoD funciona bien si elimino la siguiente línea.

 if (mPreviousHeight != 0) { /* other code is same, because mPreviousHeight is 0 when it comes first */ }