Ich muss eine sehr einfache Sache tun - herausfinden, ob die Software-Tastatur angezeigt wird. Ist das in Android möglich?
Ich muss eine sehr einfache Sache tun - herausfinden, ob die Software-Tastatur angezeigt wird. Ist das in Android möglich?
Antworten:
NEUE ANTWORT hinzugefügt am 25. Januar 2012
Seit ich die folgende Antwort geschrieben habe, hat mich jemand auf die Existenz von ViewTreeObserver und Freunden hingewiesen , APIs, die seit Version 1 im SDK lauern.
Anstatt einen benutzerdefinierten @+id/activityRoot
Layouttyp zu benötigen, besteht eine viel einfachere Lösung darin, der Stammansicht Ihrer Aktivität eine bekannte ID zuzuweisen , z. B. einen GlobalLayoutListener in den ViewTreeObserver einzubinden und von dort aus den Größenunterschied zwischen dem Ansichtsstamm Ihrer Aktivität und der Fenstergröße zu berechnen:
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
}
}
});
Verwenden eines Dienstprogramms wie:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
Einfach!
Hinweis:
Ihre Anwendung muss dieses Flag in Android Manifest setzen, da android:windowSoftInputMode="adjustResize"
sonst die oben genannte Lösung nicht funktioniert.
URSPRÜNGLICHE ANTWORT
Ja, es ist möglich, aber es ist viel schwieriger als es sein sollte.
Wenn ich mich darum kümmern muss, wann die Tastatur erscheint und verschwindet (was ziemlich oft der Fall ist), passe ich meine Layoutklasse der obersten Ebene in eine Klasse an, die überschreibt onMeasure()
. Die Grundlogik lautet: Wenn das Layout deutlich weniger als die Gesamtfläche des Fensters ausfüllt, wird wahrscheinlich eine Softtastatur angezeigt.
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);
}
}
Dann in Ihrer Aktivitätsklasse ...
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
}
...
}
((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
android.R.id.content
) versuchen , können Sie sicherer sagen, dass System
die Entität anstelle Ihrer Anwendung die Höhe ändert. Es wäre viel sicherer für das Android-Team, uns eine Pause zu gönnen und uns zumindest grundlegende Dinge über die SoftKeyboard-Eingabe mitzuteilen.
heightDiff
immer die Höhe der Aktionsleiste angegeben wird. In der neuen Antwort, die beim Testen ignoriert wurde, ob diese Höhe größer als eine Konstante ist, aber 100 Pixel für xxhdpi-Geräte wie das Nexus 4 nicht ausreichen, sollten Sie diesen Wert in DPs konvertieren, wenn Sie diese hackige Arbeit wirklich verwenden möchten. um.
Hoffentlich hilft das jemandem.
Die neue Antwort von Reuben Scratton ist großartig und sehr effizient, funktioniert aber nur, wenn Sie den windowSoftInputMode auf adjustResize einstellen. Wenn Sie es auf adjustPan einstellen, ist es immer noch nicht möglich zu erkennen, ob die Tastatur mit seinem Code-Snippet sichtbar ist oder nicht. Um dies zu umgehen, habe ich diese winzige Änderung am obigen Code vorgenommen.
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 > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
... do something here
}
}
});
TwoDScrollerView
zu ermitteln , die stackoverflow.com/a/5224088/530513 ähnelt, obwohl auch gezoomt wurde . Das Kind war kein einfaches, ImageView
sondern ein benutzerdefiniertes Layout (erweitert RelativeLayout
), konnte jedoch die Tastatur mit der empfohlenen Lösung trotz der Einstellung nicht erkennen android:windowSoftInputMode="adjustResize"
. Vielen Dank!
ActionBar
und ActionBarSherlock
. Vielen Dank! Übrigens gibt es eine Methode r.height()
:)
heightDiff > root.getRootView().getHeight() / 4
ist ein guter Wert für die Arbeit mit hochauflösenden Geräten. 100px ist zu kurz. in Nexus 5 mit 1080 x 1920 res, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // Tastatur ist in Galaxie s2 mit 480x800 res, 800 - (800-38)>? 100 = 38 800 - (410-38)>? 100 = 428 // Tastatur ist aktiv, die magische Zahl 100px ist nicht gut genug.
In Bezug auf den Computer war es für immer, aber diese Frage ist immer noch unglaublich relevant!
Also habe ich die obigen Antworten genommen und sie ein bisschen kombiniert und verfeinert ...
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);
}
});
}
Funktioniert bei mir :)
HINWEIS: Wenn Sie feststellen, dass das DefaultKeyboardDP nicht zu Ihrem Gerät passt, spielen Sie mit dem Wert und geben Sie einen Kommentar ab, damit jeder weiß, was der Wert sein soll. Schließlich erhalten wir den richtigen Wert für alle Geräte!
Weitere Informationen finden Sie in der Implementierung auf Cyborg
Entschuldigen Sie die späte Antwort, aber ich hatte eine kleine Hilfsklasse erstellt, um Open / Close-Ereignisse mit Benachrichtigungen von Hörern und anderen nützlichen Dingen zu behandeln. Vielleicht würde es jemand hilfreich finden:
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();
}
}
}
}
Anwendungsbeispiel:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
getLastKeyboardHeightInPx()
nicht die Höhe dieser Zeile enthält. Kennen Sie eine Möglichkeit, dies ebenfalls zu berücksichtigen?
Einige Verbesserungen, um zu vermeiden, dass die Sichtbarkeit von Softtastaturen auf Geräten mit hoher Dichte falsch erkannt wird:
Der Schwellenwert für den Höhenunterschied sollte als 128 dp und nicht als 128 Pixel definiert werden .
Weitere Informationen finden Sie im Google-Designdokument zu Metriken und Raster . 48 dp sind eine komfortable Größe für Touch-Objekte und 32 dp für Schaltflächen. Die generische Softtastatur sollte 4 Reihen von Tasten enthalten, daher sollte die minimale Tastaturhöhe: 32 dp * 4 = 128 dp betragen. Dies bedeutet, dass die Schwellengröße durch Multiplikation der Gerätedichte auf Pixel übertragen werden sollte. Für xxxhdpi-Geräte (Dichte 4) sollte der Schwellenwert für die Höhe der Softtastatur 128 * 4 = 512 Pixel betragen.
Höhenunterschied zwischen der Stammansicht und ihrem sichtbaren Bereich:
Höhe der Stammansicht - Höhe der Statusleiste - Höhe des sichtbaren Rahmens = Höhe der Stammansicht - Boden des sichtbaren Rahmens, da die Höhe der Statusleiste der Oberseite des sichtbaren Rahmens der Stammansicht entspricht.
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;
}
Ich habe ein wenig Zeit gebraucht, um das herauszufinden ... Ich habe einige CastExceptions ausgeführt, aber herausgefunden, dass Sie Ihr LinearLayout in der layout.xml durch den Namen der Klasse ersetzen können.
So was:
<?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>
Auf diese Weise stoßen Sie nicht auf Besetzungsprobleme.
... und wenn Sie dies nicht auf jeder Seite tun möchten, empfehle ich Ihnen, "MasterPage in Android" zu verwenden. Siehe den Link hier: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
Das Überprüfen der Höhe von Elementen ist nicht zuverlässig, da einige Tastaturen wie WifiKeyboard keine Höhe haben.
Stattdessen können Sie das Rückrufergebnis von showSoftInput () und hideSoftInput () verwenden, um den Status der Tastatur zu überprüfen. Alle Details und Beispielcode unter
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
Die Idee ist, wenn Sie Ihre Tastatur ausblenden und gleichzeitig den Status der weichen Eingabe überprüfen müssen, verwenden Sie die folgende Lösung:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
Diese Methode gibt true zurück, wenn die Tastatur vor dem Ausblenden angezeigt wurde.
Ich fand, dass eine Kombination der Methode von @ Reuben_Scratton mit der Methode von @ Yogesh am besten zu funktionieren scheint. Die Kombination ihrer Methoden würde ungefähr so ergeben:
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
}
}
});
Sie können das Verstecken von Softkeyboards mithilfe der Dekoransicht der Aktivität beobachten.
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);
}
}
Anstatt die Differenzcodierung anzunehmen, habe ich so etwas gemacht, da ich in meiner Anwendung keine Menüoptionen hatte.
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
}
}
});
Es gibt auch eine Lösung mit Systemeinfügungen, die jedoch nur mit API >= 21
( Android L
) funktioniert . Angenommen, Sie haben BottomNavigationView
, welches Kind von ist, LinearLayout
und Sie müssen es ausblenden, wenn die Tastatur angezeigt wird:
> LinearLayout
> ContentView
> BottomNavigationView
Alles was Sie tun müssen, ist Folgendes zu erweitern LinearLayout
:
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;
}
}
Die Idee ist, dass bei der Anzeige der Tastatur die Systemeinfügungen mit ziemlich großem .bottom
Wert geändert werden.
Es gibt eine versteckte Methode, die dabei helfen kann InputMethodManager.getInputMethodWindowVisibleHeight
. Aber ich weiß nicht, warum es versteckt ist.
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()
}
}
Keine dieser Lösungen funktioniert für Lollipop so wie sie ist. In Lollipop activityRootView.getRootView().getHeight()
enthält die Höhe der Schaltflächenleiste, während das Messen der Ansicht nicht. Ich habe die beste / einfachste Lösung oben für die Arbeit mit Lollipop angepasst.
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
}
}
});
Ich bin gerade auf einen Fehler gestoßen, als ich die meisten der oben genannten Lösungen verwendet habe, die das Hinzufügen einer festen Nummer vorschlagen.
S4 hat eine hohe Auflösung, was dazu führte, dass die Höhe der Navigationsleiste 100 Pixel betrug. Daher dachte meine App, dass die Tastatur ständig geöffnet ist.
Angesichts der neuen hochauflösenden Telefone halte ich die Verwendung eines fest codierten Werts auf lange Sicht für keine gute Idee.
Ein besserer Ansatz, den ich nach einigen Tests auf verschiedenen Bildschirmen und Geräten gefunden habe, war die Verwendung des Prozentsatzes. Ermitteln Sie den Unterschied zwischen decorView und Ihrem App-Inhalt und überprüfen Sie anschließend, wie viel Prozent dieses Unterschieds ausmachen. Nach den Statistiken, die ich erhalten habe, nimmt die meiste Navigationsleiste (unabhängig von Größe, Auflösung usw.) zwischen 3% und 5% des Bildschirms ein. Wenn die Tastatur geöffnet ist, nimmt sie zwischen 47% und 55% des Bildschirms ein.
Als Fazit bestand meine Lösung darin, zu überprüfen, ob der Unterschied mehr als 10% beträgt, dann gehe ich davon aus, dass die Tastatur offen ist.
Ich habe eine kleine Variante von Reubans Antwort verwendet, die sich unter bestimmten Umständen als hilfreicher erwies, insbesondere bei hochauflösenden Geräten.
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
}
}
});
R.id.activityRoot
, können Sie einfach android.R.id.content
genau das verwenden , was Sie benötigen.
In Bezug auf den Computer war es für immer, aber diese Frage ist immer noch unglaublich relevant! Also habe ich die obigen Antworten genommen und sie ein bisschen kombiniert und verfeinert ...
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);
}
});
}
Für mich geht das.
Versuche dies:
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 ... \\
}
}
});
Meine Antwort ist im Grunde die gleiche wie die von Kachi, aber ich habe sie in eine nette Hilfsklasse eingepackt, um die Art und Weise zu bereinigen, wie sie in meiner App verwendet wird.
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);
}
}
Sie können dies verwenden, um Tastaturänderungen überall in der App wie folgt zu erkennen:
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
}
}
});
Hinweis: Verwenden Sie nur einen der "Register" -Aufrufe. Sie arbeiten alle gleich und sind nur zur Vereinfachung da
Sie können dies versuchen, arbeiten Sie gut für mich:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
Ich hatte Schwierigkeiten, den Tastaturstatus beizubehalten, wenn ich die Ausrichtung von Fragmenten in einem Viewpager änderte. Ich bin mir nicht sicher warum, aber es scheint nur wackelig zu sein und verhält sich anders als eine Standardaktivität.
Um den Tastaturstatus in diesem Fall beizubehalten, sollten Sie zuerst android:windowSoftInputMode = "stateUnchanged"
Ihren hinzufügenAndroidManifest.xml
. Möglicherweise stellen Sie jedoch fest, dass dies nicht das gesamte Problem löst. Die Tastatur wurde für mich nicht geöffnet, wenn sie zuvor vor einer Änderung der Ausrichtung geöffnet wurde. In allen anderen Fällen schien das Verhalten korrekt zu sein.
Dann müssen wir eine der hier genannten Lösungen implementieren. Das sauberste, das ich gefunden habe, war das von George Maisuradze - verwenden Sie den booleschen Rückruf von hideSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
Ich habe diesen Wert in der onSaveInstanceState
Methode meines Fragments gespeichert und abgerufen onCreate
. Dann zeigte ich gewaltsam die Tastatur, onCreateView
wenn sie einen Wert von hattetrue
(sie gibt true zurück, wenn die Tastatur sichtbar ist, bevor sie vor der Zerstörung des Fragments tatsächlich ausgeblendet wurde).
Hier ist meine Lösung, und es funktioniert. Anstatt nach der Pixelgröße zu suchen, überprüfen Sie einfach, ob sich die Höhe der Inhaltsansicht geändert hat oder nicht:
// 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();
}
Mach keinen harten Code. Am besten müssen Sie die Größe Ihrer Ansichten ändern, während Sie sich mit KeyBord Show auf EditText konzentrieren. Sie können dies tun, indem Sie der Manifest-Datei mithilfe des folgenden Codes die Eigenschaft zum Ändern der Größe für Aktivitäten hinzufügen.
android:windowSoftInputMode="adjustResize"
Es gibt eine direkte Methode, um dies herauszufinden. Außerdem sind keine Layoutänderungen erforderlich.
Es funktioniert also auch im immersiven Vollbildmodus.
Der Trick besteht darin, dass Sie versuchen, die Softtastatur auszublenden oder anzuzeigen und das Ergebnis dieses Versuchs zu erfassen.
Keine Panik, dies zeigt oder versteckt die Tastatur nicht wirklich. Wir fragen nur nach dem Staat.
Um auf dem neuesten Stand zu bleiben, können Sie den Vorgang einfach, z. B. alle 200 Millisekunden, mit einem Handler wiederholen.
Eine Implementierung finden Sie hier: https://stackoverflow.com/a/27567074/2525452
Ich denke, diese Methode wird Ihnen helfen herauszufinden, ob Keybord sichtbar ist oder nicht.
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;
}
}
Die neue Antwort von Reuben Scratton (Berechnung des HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) funktioniert nicht in der Aktivität, wenn Sie den durchscheinenden Statusleistenmodus einstellen.
Wenn Sie eine durchscheinende Statusleiste verwenden, activityRootView.getHeight()
ändert sich das Wetter nie, wenn die Softtastatur sichtbar ist. Es wird immer die Höhe der Aktivität und die Statusleiste zurückgegeben.
Zum Beispiel, Nexus 4, Android 5.0.1, android:windowTranslucentStatus
auf true gesetzt, wird es 1184 für immer zurückgeben, selbst die ime haben opend. Wenn Sie einstellenandroid:windowTranslucentStatus
auf false setzen, wird die Höhe korrekt zurückgegeben. Wenn ich unsichtbar bin, wird 1134 zurückgegeben (ohne die Statusleiste). Schließen Sie das IM, es gibt möglicherweise 5xx zurück (abhängig von der Größe des Ime).
Ich weiß nicht, ob dies ein Fehler ist. Ich habe 4.4.4 und 5.0.1 ausprobiert. Das Ergebnis ist dasselbe.
Bis jetzt, als zweithäufigste Antwort, ist Kachis Lösung der sicherste Weg, um die Höhe von ime zu berechnen. Hier ist eine Kopie:
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
}
}
});
Eine Methode, die keinen LayoutListener benötigt
In meinem Fall möchte ich den Status der Tastatur speichern, bevor ich mein Fragment ersetze. Ich rufe die Methode hideSoftInputFromWindow von aufonSaveInstanceState
, die die Tastatur schließt und mir zurückgibt, ob die Tastatur sichtbar war oder nicht.
Diese Methode ist unkompliziert, kann jedoch den Status Ihrer Tastatur ändern.
Ich weiß, dass dies ein alter Beitrag ist, aber ich denke, dies ist der einfachste Ansatz, den ich kenne, und mein Testgerät ist Nexus 5. Ich habe es auf anderen Geräten nicht ausprobiert. Hoffe, dass andere ihren Ansatz teilen, wenn sie meinen Code nicht gut finden :)
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 gibt einen Booleschen Wert zurück.
Vielen Dank,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
Mit der obigen Funktion überprüfe ich, ob eine Tastatur sichtbar ist. Wenn ja, dann schließe ich es.
Unten sehen Sie die beiden erforderlichen Methoden.
Definieren Sie zunächst die Höhe des bearbeitbaren Fensters in 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;
//
}
Fügen Sie dann eine boolesche Methode hinzu, die die Fensterhöhe an dieser Instanz abruft. Wenn es nicht mit dem Original übereinstimmt (vorausgesetzt, Sie ändern es unterwegs nicht ...), ist die Tastatur geöffnet.
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!
Ich weiß, wie genau Sie feststellen können, ob die Tastatur versteckt ist oder nicht.
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;
}
Dies funktioniert für Tablets. Wenn die Navigationsleiste horizontal angezeigt wird.