Comment vérifier la visibilité du clavier de logiciel sur Android?
je dois faire une chose très simple - savoir si le clavier du logiciel est affiché. Est-ce possible sur Android?
30 réponses
nouvelle réponse ajouté le 25 janvier 2012
depuis l'écriture de la réponse ci-dessous, quelqu'un m'a clued in à l'existence de ViewTreeObserver et des amis, APIs qui se cachent dans le SDK depuis la version 1.
plutôt que d'exiger un type de mise en page personnalisé, une solution beaucoup plus simple est de donner à la vue racine de votre activité un ID connu, par exemple @+id/activityRoot
, hook a GlobalLayoutListener dans le ViewTreeObserver, et à partir de là calculer la différence de taille entre la racine de vue de votre activité et la taille de la fenêtre:
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
}
}
});
utilisant un utilitaire tel que:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
facile!
Note:
Votre application doit mettre ce drapeau dans le manifeste Android android:windowSoftInputMode="adjustResize"
sinon la solution ci-dessus ne fonctionnera pas.
ORIGINAL ANSWER
Oui c'est possible, mais c'est beaucoup plus difficile que ça devrait l'être.
si j'ai besoin de me soucier du moment où le clavier apparaît et disparaît (ce qui est assez souvent), alors ce que je fais c'est personnaliser ma classe de mise en page de haut niveau en une classe qui remplace onMeasure()
. La logique de base est que si la disposition se trouve remplir considérablement moins que la surface totale de la fenêtre, alors un clavier souple est probablement affiché.
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);
}
}
Ensuite, dans votre classe d'Activité...
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
}
...
}
donc j'espère que ça aidera quelqu'un.
la nouvelle réponse que Reuben Scratton a donnée est grande et vraiment efficace, mais cela ne fonctionne vraiment que si vous réglez votre windowSoftInputMode pour ajuster vos dimensions. Si vous le définissez à adjustPan, il n'est toujours pas possible de détecter si le clavier est visible ou non en utilisant son code snippet. Pour contourner cela, j'ai fait cette petite modification au code ci-dessus.
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
}
}
});
désolé pour la réponse tardive, mais j'avais créé une petite classe helper pour gérer les événements ouverts / fermés avec les auditeurs de notification et d'autres choses utiles, peut-être quelqu'un le trouverait utile:
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();
}
}
}
}
exemple D'Usage:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
il a été pour toujours en termes d'ordinateur, mais cette question est encore incroyablement pertinente!
donc j'ai pris les réponses ci-dessus et je les ai combinées et peaufinées un peu...
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);
}
});
}
Fonctionne pour moi :)
NOTE: Si vous remarquez que le DefaultKeyboardDP ne correspond pas à votre appareil jouer avec la valeur et poster un commentaire pour tout le monde de savoir ce qui devrait être le valeur... finalement, nous allons obtenir la valeur correcte pour s'adapter à tous les appareils!
quelques améliorations pour éviter de détecter à tort la visibilité du clavier souple sur les appareils haute densité:
-
Le Seuil de différence de hauteur doit être défini comme 128 dp , et non 128 pixels .
Se référer à Google design doc à propos de la métrique et la grille , 48 dp est la taille confortable pour l'objet tactile et 32 dp est un minimum pour les boutons. Le clavier souple générique devrait comprendre 4 rangées de touches, de sorte que la hauteur minimale du clavier devrait être: 32 dp * 4 = 128 dp , ce qui signifie que la taille de seuil devrait être transférée aux pixels par la densité de l'appareil multipliée. Pour les périphériques xxxhdpi (densité 4), le seuil de hauteur du clavier souple devrait être de 128 * 4 = 512 pixels. -
différence de hauteur entre root view et sa surface visible:
vue de la racine hauteur-barre d'état hauteur-cadre visible hauteur = vue de la racine bas-cadre visible bas, puisque la hauteur de la barre d'état est égale au sommet du cadre visible vue de la racine.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; }
j'ai mis un peu de temps pour comprendre... Je l'ai lancé quelques CastExceptions, mais j'ai compris que vous pouvez remplacer vous LinearLayout dans le layout.xml avec le nom de la classe.
comme ceci:
<?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 cette façon, vous ne rencontrerez pas de problèmes de distribution.
... et si vous ne voulez pas le faire sur chaque page, je vous recommande d'utiliser "MasterPage dans Android". Voir le lien ici: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
l'idée est, si vous avez besoin de cacher votre clavier et vérifier l'état d'entrée soft En même temps, utiliser la solution suivante:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
cette méthode retourne true si le clavier était affiché avant de se cacher.
vérifier la hauteur des éléments n'est pas fiable car certains claviers comme WifiKeyboard ont une hauteur nulle.
à la place, vous pouvez utiliser le résultat de rappel de showSoftInput() et hideSoftInput() pour vérifier l'état du clavier. Tous les détails et le code d'exemple à
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
au lieu de supposer le codage de différence, j'ai fait quelque chose comme ça, car je n'avais pas d'options de menu dans mon application.
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
}
}
});
j'ai trouvé qu'une combinaison de la méthode de @Reuben_Scratton avec la méthode de @Yogesh semble fonctionner le mieux. En combinant leurs méthodes, on obtiendrait quelque chose comme ceci:
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
}
}
});
vous pouvez observer la peau de softkeyboard en utilisant decorview activity.
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);
}
}
il y a aussi solution avec insets système, mais il fonctionne seulement avec API >= 21
( Android L
). Dites que vous avez BottomNavigationView
, qui est enfant de LinearLayout
et vous devez le cacher lorsque le clavier est affiché:
> LinearLayout
> ContentView
> BottomNavigationView
Tout ce que vous devez faire est d'étendre LinearLayout
dans une telle manière:
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;
}
}
l'idée est que lorsque le clavier est affiché, les insets du système sont changés avec une assez grande valeur .bottom
.
Aucune de ces solutions fonctionnent pour Lollipop. Dans Lollipop activityRootView.getRootView().getHeight()
comprend la hauteur de la barre de bouton, tandis que la mesure de la vue ne le fait pas. J'ai adapté la meilleure / solution la plus simple ci-dessus pour travailler avec 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
}
}
});
j'ai utilisé une petite variante de la réponse de Reuban, qui s'est avérée plus utile dans certaines circonstances, en particulier avec les dispositifs à haute résolution.
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
}
}
});
il a été pour toujours en termes de l'ordinateur, mais cette question est encore incroyablement pertinente! J'ai donc pris les réponses ci-dessus et les ai combinées et raffinées un peu...
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);
}
});
}
ça me va.
ma réponse est essentiellement la même que la réponse de Kachi, mais je l'ai enveloppé dans une classe helper nice pour nettoyer la façon dont il est utilisé tout au long de mon application.
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);
}
}
vous pouvez utiliser ceci pour détecter des changements de clavier n'importe où dans l'application comme ceci:
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
}
}
});
Note: n'utilisez qu'un des appels "register". Ils travaillent tous les mêmes et ne sont là que pour la commodité
vous pouvez essayer ce, pour moi:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
je viens de rencontrer un bug en utilisant la plupart des solutions ci-dessus qui suggèrent d'ajouter un nombre fixe.
S4 is a un dpi élevé qui a pour résultat que la hauteur de la barre de navigation est de 100px d'où mon application pensant que le clavier est ouvert tout le temps.
donc avec tous les nouveaux téléphones high res libérés, je crois que l'utilisation d'une valeur codée dure n'est pas une bonne idée à long terme.
Une meilleure approche que j'ai trouvé après certains tests sur divers écrans et appareils devaient utiliser le pourcentage. Obtenez la différence entre le contenu de decorView et ur app et vérifiez ensuite quel est le pourcentage de cette différence. D'après les statistiques que j'ai reçues, la plupart des nav bar(indépendamment de la taille, la résolution, etc..) prendra entre 3% et 5% de l'écran. Si le clavier est ouvert, il était de 47% à 55% de l'écran.
en conclusion, ma solution a été de vérifier si la diff est supérieure à 10% alors je assumer ses un clavier ouvert.
j'avais de la difficulté à maintenir l'état du clavier lorsque je changeais l'orientation des fragments dans un viewpager. Je ne sais pas pourquoi, mais ça a l'air bizarre et agit différemment d'une activité standard.
Pour maintenir l'état du clavier, dans ce cas, vous devez d'abord ajouter android:windowSoftInputMode = "stateUnchanged"
à votre AndroidManifest.xml
. Vous remarquerez peut-être, cependant, que cela ne résout pas en fait tout le problème -- le clavier ne s'est pas ouvert pour moi s'il avait été ouvert auparavant. changement d'orientation. Dans tous les autres cas, le comportement semblait correcte.
Ensuite, nous devons mettre en œuvre l'une des solutions mentionnées ici. Le plus propre que j'ai trouvé était celui de George Maisuradze -- utilisez le rappel booléen de hideSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
j'ai stocké cette valeur dans la méthode de mon Fragment onSaveInstanceState
et je l'ai récupérée onCreate
. Puis, j'ai montré de force le clavier dans onCreateView
s'il avait une valeur de true
(il renvoie true si le clavier est visible avant de le cacher avant la destruction du Fragment).
essayez ceci:
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 ... \
}
}
});
Il ya une méthode cachée peut aider pour cela, InputMethodManager.getInputMethodWindowVisibleHeight
. Mais je ne sais pas pourquoi il est caché.
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()
}
}
voici ma solution, et ça marche. Au lieu de chercher la taille des pixels, vérifiez simplement que la hauteur de la vue de contenu a changé ou non:
// 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();
}
ne crée pas de code dur. La meilleure façon est que vous devez redimensionner vos vues alors que sur Get Focus on EditText with KeyBord Show. Vous pouvez le faire en ajoutant la propriété redimensionner sur l'activité dans le fichier manifeste en utilisant le code ci-dessous.
android:windowSoftInputMode="adjustResize"
Il y a une méthode directe pour le savoir. Et, il ne nécessite pas de modifications de Mise en page.
Donc, il fonctionne aussi en mode plein écran immersif.
L'astuce est que vous essayez de cacher ou de montrer le clavier doux et de capturer le résultat de cet essai.
Pas de panique, ce n'est pas vraiment montrer ou cacher le clavier. Nous vous demandons juste de l'état.
Séjourner mise à jour, vous pouvez simplement répéter l'opération, par exemple toutes les 200 millisecondes, en utilisant un Handler.
Vous trouvez une implémentation ici: https://stackoverflow.com/a/27567074/2525452
je pense que cette méthode vous aidera à découvrir si keybord est visible ou non.
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;
}
}
la nouvelle réponse de Reuben Scratton (calculez le HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) ne fonctionnera pas en activité si vous définissez le mode barre d'état translucide.
si vous utilisez la barre d'état translucide, activityRootView.getHeight()
ne changera jamais le temps le clavier souple est visible. il retournera toujours la barre de hauteur d'activité et de statut.
par exemple, Nexus 4, Android 5.0.1, mettre android:windowTranslucentStatus
à true, il retournera 1184 pour toujours, même l'EMI ont opend. Si vous mettez android:windowTranslucentStatus
à false, il retournera la hauteur correctement, si je suis invisible, il retourne 1134 (ne pas inclure la barre de statut) փfermer l'EMI, il retournera 5xx peut-être (dépend de la hauteur de l'EMI)
Je ne sais pas la météo c'est un bug, j'ai essayé sur 4.4.4 et 5.0.1, le résultat est le même.
donc, jusqu'à présent, la deuxième réponse la plus convenue, la solution de Kachi sera le moyen le plus sûr de calculer la hauteur d'ime. Voici une copie:
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
}
}
});
, Une méthode qui n'a pas besoin d'un LayoutListener
Dans mon cas, je voudrais enregistrer l'état du clavier avant de remplacer mon Fragment. J'appelle la méthode hideSoftInputFromWindow de onSaveInstanceState
, qui ferme le clavier et me renvoie si le clavier était visible ou non.
Cette méthode est simple, mais peut modifier l'état de votre clavier.
je sais que c'est un vieux post mais je pense que c'est l'approche la plus simple que je connaisse et mon dispositif d'essai est Nexus 5. Je n'ai pas essayé les autres appareils. Espérons que d'autres viendront partager leur approche, s'ils trouvent que mon code n'est pas bon :)
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 retourne booléen.
Merci,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
la fonction ci-dessus est celle que j'utilise pour vérifier si un clavier est visible. Si c'est le cas, je le ferme.
La rubriqueci-dessous indique les deux méthodes requises.
tout d'abord, définissez la hauteur de fenêtre exploitable dans 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;
//
}
ensuite, ajouter une méthode booléenne qui obtient la hauteur de fenêtre à cette instance. S'il ne correspond pas à l'original (en supposant que vous ne le changiez pas en cours de route...) ensuite, le clavier est ouvrir.
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!
je sais à quel point vous pouvez déterminer si le clavier est caché ou non.
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;
}
cela fonctionne pour les comprimés. Lorsque la barre de navigation est affichée horizontalement.