Android: détecter softkeyboard ouvert
quand le clavier souple s'ouvre, je veux une vue de défilement vers le bas vers le bas.
pour cela je peux utiliser: fullScroll(View.FOCUS_DOWN);
mais comment puis-je lancer cette commande après le déclenchement de l'événement d'ouverture du clavier souple?
8 réponses
Par ce post et ce post sur android, les développeurs il ne semble pas comme il est possible de faire ce que vous voulez. Vous pouvez ré-examiner votre cas d'utilisation pour ce que vous faites. Peut-être qu'un des drapeaux softInputMode
vous conviendra.
voici ma solution:
1/ Une interface simple
public interface KeyboardVisibilityListener {
void onKeyboardVisibilityChanged(boolean keyboardVisible);
}
2 / une méthode utilitaire (mettez-la où vous voulez, par exemple dans une classe appelée 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 / Utilisation d'une activité de cette manière (une bonne place est à onCreate):
KeyboardUtil.setKeyboardVisibilityListener(this, mKeyboardVisibilityListener);
en regardant la date, vous avez peut-être une solution pour votre question, sinon:
Voici la même réponse que j'ai faite à une autre question liée : y a-t-il un moyen de dire si le clavier est affiché?
mais je copie la réponse complète ici pour éviter les liens morts:
s'il vous Plaît cochez la case les Modifications de la Configuration pour votre Activité
ceci pour votre AndroidManifest.xml
et ceci pour votre activité classe http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged(android.content.res.Configuration)
, Vous devrez @Override public méthode onConfigurationChanged (android.contenu.res.Configuration de votre Activité pour être en mesure de gérer, par exemple, ces valeurs:
hardKeyboardHidden ,
clavier ,
keyboardHidden
pour toutes les valeurs possibles, cocher http://developer.android.com/reference/android/content/res/Configuration.html
Vous y verrez quelque chose comme ceci:
HARDKEYBOARDHIDDEN_NO
HARDKEYBOARDHIDDEN_UNDEFINED
HARDKEYBOARDHIDDEN_YES
KEYBOARDHIDDEN_NO
KEYBOARDHIDDEN_UNDEFINED
KEYBOARDHIDDEN_YES
KEYBOARD_12KEY
KEYBOARD_NOKEYS
KEYBOARD_QWERTY
KEYBOARD_UNDEFINED
Là aussi vous pourrez lire quelque chose comme ceci:
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.
mise à jour:
voici un échantillon spécifique 1519170920" de ce dont je parle:
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();
}
}
j'espère que cela vous aider à
la seule façon dont j'ai pu contourner ce problème est de configurer l'android de mon activité:windowSoftInputMode=" adjustResize "et ensuite d'intégrer une" vue détecteur " personnalisée dans la mise en page pour gérer un changement de taille de conteneur et de propager cela comme un événement personnalisé (via un écouteur) pour le clavier doux on/off.
le post suivant décrit une approche pour la mettre en œuvre: EditText ne déclenche pas de changements quand on appuie sur le dos
Cela fonctionne pour moi
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<oldBottom){
// Keyboard Open
viewToHide.setVisibility(View.GONE);
}
}else{
// show
viewToHide.setVisibility(View.VISIBLE);
}
}
});
où parent est la mise en page principale, viewToHide est la vue qui montre ou se cache lorsque le clavier est affiché, et host,folder,user et pass sont les textes édités de mon formulaire.
et ceci dans le manifeste
android:windowSoftInputMode="stateHidden|adjustResize"
Espérons que cette aide
voici ma solution. Il n'a pas besoin d'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);
}
}
alors je viens d'étendre mon activité à partir de cette activité et de passer outre les méthodes onKeyboardClosed/onKeyboardOpen.
pour ce que j'avais l'habitude de faire:
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 (verheye.francesco@gmail.com)
*/
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 (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();
}
}
}
}
et dans votre Activity
ou fragment
appelez cette méthode dans 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);
}
}
});
}
});
}
profitez de votre code:)
la réponse de @BoD fonctionne très bien si je supprime la ligne suivante.
if (mPreviousHeight != 0) {
/* other code is same, because
mPreviousHeight is 0 when it comes first */
}