SoftKeyboard abrir y cerrar escucha en una actividad en Android?

Tengo Activity donde hay 5 EditText . Cuando el usuario haga clic en primer EditText entonces teclado suave abierto para ingresar algún valor en él. Quiero fijar el otro Visibilidad de la View a Gone cuando el teclado suave abierto cuando el usuario hace clic en primer EditText y cuando el cierre suave del teclado del mismo EditText en prensa posterior entonces quiero fijar el otro visibilidad de la View a visible.

¿Hay algún oyente o callback o cualquier hack cuando el teclado EditText abre al hacer clic en el primer EditText en Android?

Esto sólo funciona cuando android:windowSoftInputMode de su actividad se establece en adjustResize en el manifiesto. Puede utilizar un oyente de diseño para ver si el diseño raíz de su actividad se redimensiona mediante el teclado.

Utilizo algo como la siguiente clase base para mis actividades:

 public class BaseActivity extends Activity { private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight(); int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(BaseActivity.this); if(heightDiff <= contentViewTop){ onHideKeyboard(); Intent intent = new Intent("KeyboardWillHide"); broadcastManager.sendBroadcast(intent); } else { int keyboardHeight = heightDiff - contentViewTop; onShowKeyboard(keyboardHeight); Intent intent = new Intent("KeyboardWillShow"); intent.putExtra("KeyboardHeight", keyboardHeight); broadcastManager.sendBroadcast(intent); } } }; private boolean keyboardListenersAttached = false; private ViewGroup rootLayout; protected void onShowKeyboard(int keyboardHeight) {} protected void onHideKeyboard() {} protected void attachKeyboardListeners() { if (keyboardListenersAttached) { return; } rootLayout = (ViewGroup) findViewById(R.id.rootLayout); rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener); keyboardListenersAttached = true; } @Override protected void onDestroy() { super.onDestroy(); if (keyboardListenersAttached) { rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener); } } } 

La actividad de ejemplo siguiente utiliza esto para ocultar una vista cuando se muestra el teclado y volver a mostrarlo cuando el teclado está oculto.

El diseño xml:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rootLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > <!-- omitted for brevity --> </ScrollView> <LinearLayout android:id="@+id/bottomContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <!-- omitted for brevity --> </LinearLayout> </LinearLayout> 

Y la actividad:

 public class TestActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_activity); attachKeyboardListeners(); } @Override protected void onShowKeyboard(int keyboardHeight) { // do things when keyboard is shown bottomContainer.setVisibility(View.GONE); } @Override protected void onHideKeyboard() { // do things when keyboard is hidden bottomContainer.setVisibility(View.VISIBLE); } } 

Como Vikram señaló en los comentarios, la detección de si el teclado se muestra o ha desaparecido sólo es posible con algunos hacks feo.

Tal vez sea suficiente para establecer un oyente de enfoque en el edittext :

 yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { //got focus } else { //lost focus } } }); 

Pieza de pastel con esta impresionante biblioteca: https://android-arsenal.com/details/1/2519

Probado en Android M

La versión min SDK de soporte es 14 para 2.0.0

La respuesta de Jaap no funcionará para AppCompatActivity. En su lugar obtener la altura de la barra de estado y la barra de navegación, etc y comparar con el tamaño de la ventana de su aplicación.

Al igual que:

  private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // navigation bar height int navigationBarHeight = 0; int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { navigationBarHeight = getResources().getDimensionPixelSize(resourceId); } // status bar height int statusBarHeight = 0; resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { statusBarHeight = getResources().getDimensionPixelSize(resourceId); } // display window size for the app layout Rect rect = new Rect(); getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); // screen height - (user app height + status + nav) ..... if non-zero, then there is a soft keyboard int keyboardHeight = rootLayout.getRootView().getHeight() - (statusBarHeight + navigationBarHeight + rect.height()); if (keyboardHeight <= 0) { onHideKeyboard(); } else { onShowKeyboard(keyboardHeight); } } }; 

Para Actividad:

  final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top); if (heightDiff > 100) { //enter your code here }else{ //enter code for hid } } }); 

Para Fragmento:

  view = inflater.inflate(R.layout.live_chat_fragment, null); view.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. view.getWindowVisibleDisplayFrame(r); int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top); if (heightDiff > 500) { // if more than 100 pixels, its probably a keyboard... } } }); 

Utilice esta clase,

 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<EditText> 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 ([email protected]) */ private void initEditTexts(ViewGroup viewgroup) { if(editTextList == null) editTextList = new ArrayList<EditText>(); 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 ([email protected]) */ @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(); } } } } 

En Android Manifest , android:windowSoftInputMode="adjustResize" es necesario.

 /* Somewhere else in your code */ RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root InputMethodManager im = (InputMethodManager)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() { // Code here } @Override public void onSoftKeyboardShow() { // Code here } }); /* Open or close the soft keyboard easily */ softKeyboard.openSoftKeyboard(); softKeyboard.closeSoftKeyboard(); /* Prevent memory leaks:*/ @Override public void onDestroy() { super.onDestroy(); softKeyboard.unRegisterSoftKeyboardCallback(); } 

PS – Completamente tomado de aquí .

Si puede, intente extender el método EditText y anular el método 'onKeyPreIme'.

 @Override public void setOnEditorActionListener(final OnEditorActionListener listener) { mEditorListener = listener; //keep it for later usage super.setOnEditorActionListener(listener); } @Override public boolean onKeyPreIme(final int keyCode, final KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { if (mEditorListener != null) { //you can define and use custom listener, //OR define custom R.id.<imeId> //OR check event.keyCode in listener impl //* I used editor action because of ButterKnife @ mEditorListener.onEditorAction(this, android.R.id.closeButton, event); } } return super.onKeyPreIme(keyCode, event); } 

¿Cómo se puede ampliar:

  1. Implementar onFocus escuchando y declarar 'onKeyboardShown'
  2. Declarar 'onKeyboardHidden'

Creo que el recalcular de la altura de la pantalla no es 100% satisfactorio como se mencionó anteriormente. Para ser claros, la sustitución de 'onKeyPreIme' no se llama en 'ocultar soft keyboard programatically' métodos, pero si lo está haciendo en cualquier lugar, debe hacer 'onKeyboardHidden' lógica allí y no crear una solución integral.

 public class MainActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mainactivity); attachKeyboardListeners(); .... yourEditText1.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { yourEditText2.setVisibility(View.GONE); yourEditText3.setVisibility(View.GONE); yourEditText4.setVisibility(View.GONE); yourEditText5.setVisibility(View.GONE); } else { yourEditText2.setVisibility(View.VISIBLE); yourEditText3.setVisibility(View.VISIBLE); yourEditText4.setVisibility(View.VISIBLE); yourEditText5.setVisibility(VISIBLE); } } }); } } 

Desafortunadamente, no tengo una reputación suficientemente alta para comentar la respuesta de Jaap van Hengstum. Pero he leído algunos comentarios de personas, teniendo el problema de que contentViewTop es siempre 0 y que onShowKeyboard(...) siempre se llama.

Tuve el mismo problema y descubrí el problema que tenía. Utilicé una AppCompatActivity lugar de una actividad "normal". En este caso Window.ID_ANDROID_CONTENT refiere a un ContentFrameLayout y no a FrameLayout con el valor superior derecho. En mi caso estaba bien usar la Activity normal, si tienes que usar otro tipo de actividad (acabo de probar AppCompatActivity , tal vez también sea un problema con otros tipos de acitivy como la FragmentActivity ), tienes que acceder a la FrameLayout , que es un ancestro de ContentFrameLayout .

Para el caso de adjustResize y FragmentActivity la solución aceptada de @Jaap no funciona para mí.

Aquí está mi solución:

 private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { private int contentDiff; private int rootHeight; @Override public void onGlobalLayout() { View contentView = getWindow().findViewById(Window.ID_ANDROID_CONTENT); if (rootHeight != mDrawerLayout.getRootView().getHeight()) { rootHeight = mDrawerLayout.getRootView().getHeight(); contentDiff = rootHeight - contentView.getHeight(); return; } int newContentDiff = rootHeight - contentView.getHeight(); if (contentDiff != newContentDiff) { if (contentDiff < newContentDiff) { onShowKeyboard(newContentDiff - contentDiff); } else { onHideKeyboard(); } contentDiff = newContentDiff; } } }; 

Cuando el teclado muestre

 rootLayout.getHeight() < rootLayout.getRootView().getHeight() - getStatusBarHeight() 

Es cierto, sino ocultar

Puedes probarlo:

 private void initKeyBoardListener() { // Минимальное значение клавиатуры. Threshold for minimal keyboard height. final int MIN_KEYBOARD_HEIGHT_PX = 150; // Окно верхнего уровня view. Top-level window decor view. final View decorView = getWindow().getDecorView(); // Регистрируем глобальный слушатель. Register global layout listener. decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { // Видимый прямоугольник внутри окна. Retrieve visible rectangle inside window. private final Rect windowVisibleDisplayFrame = new Rect(); private int lastVisibleDecorViewHeight; @Override public void onGlobalLayout() { decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame); final int visibleDecorViewHeight = windowVisibleDisplayFrame.height(); if (lastVisibleDecorViewHeight != 0) { if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) { Log.d("Pasha", "SHOW"); } else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) { Log.d("Pasha", "HIDE"); } } // Сохраняем текущую высоту view до следующего вызова. // Save current decor view height for the next call. lastVisibleDecorViewHeight = visibleDecorViewHeight; } }); } 

Diferente aplicación de un suave-teclado-oyente que no confía en WINDOW-RESIZING y por lo tanto también funciona muy bien en el mundo de múltiples ventanas. Tiene sus propias peculiaridades, por supuesto, pero no son nada en comparación con el completo rotura que es multi-ventana y ventana de cambio de tamaño de detección en conjunto.

https://github.com/sqrt1764/AndroidSoftKeyboardListener

Apreciaría ideas para mejoras!

 private boolean isKeyboardShown = false; private int prevContentHeight = 0; private ViewGroup contentLayout; private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int contentHeight = contentLayout.getHeight(); int rootViewHeight = contentLayout.getRootView().getHeight(); if (contentHeight > 0) { if (!isKeyboardShown) { if (contentHeight < prevContentHeight) { isKeyboardShown = true; onShowKeyboard(rootViewHeight - contentHeight); } } else { if (contentHeight > prevContentHeight) { isKeyboardShown = false; onHideKeyboard(); } } prevContentHeight = contentHeight; } } }; 

He modificado la respuesta aceptada de Jaap un poco. Pero en mi caso, hay pocas suposiciones como android:windowSoftInputMode=adjustResize y el teclado no aparece al principio cuando se inicia la aplicación. Y también, supongo que la pantalla en relación con coincide con la altura de los padres.

contentHeight > 0 esta comprobación me proporciona saber si la pantalla correspondiente está oculta o se muestra que aplica el evento del teclado para escuchar esta pantalla específica. También paso la vista de disposición de la pantalla relativa en attachKeyboardListeners(<your layout view here>) en el método onCreate() mi actividad principal. Cada vez que cambia la altura de la pantalla, la prevContentHeight variable prevContentHeight para comprobar más tarde si se muestra o se oculta el teclado.

Para mí, hasta ahora se ha trabajado bastante bien. Espero que funcione para otros también.

  • Cómo agregar la preferencia del método de entrada personalizada a la aplicación de configuración de Android?
  • Ocultar Soft Keyboard en la aplicación para Android Desde fragmentos de ViewPager
  • Cierra / oculta el teclado suave de Android en MvxFragment
  • Posicionamiento de EditText por encima del teclado
  • ¿Hay alguna forma de obtener un teclado de software de Android que tenga sólo números (sin decimales, espacios) con código Java?
  • Cómo enviar evento de puntero en Android
  • Después de pulsar una tecla, la vista desciende, sólo en S3
  • Retener soft-input / IME state en el cambio de orientación
  • Programaticamente Ocultar Soft Keyboard en ViewPager.OnPageChangeListener onPageSelected ()?
  • ¿Cómo puedo mostrar mi diseño de desplazamiento por encima del teclado?
  • La barra de espacio de Android no funciona
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.