559 Stimmen

Wie kann man die Sichtbarkeit der Software-Tastatur in Android überprüfen?

Ich muss etwas ganz Einfaches tun - herausfinden, ob die Software-Tastatur angezeigt wird. Ist dies in Android möglich?

9 Stimmen

Obwohl die Antwort von Reuben Scratton gut ist, scheint sie auf einem Tablet nicht zu funktionieren. Ich habe die Prüfung diff>128 durch diff>screenHeight/3 ersetzt.

2 Stimmen

Die Antwort von Reuben Scratton war gut, aber ich brauchte die Anpassung von KaChi, um sie wirklich nutzen zu können.

0 Stimmen

Anstatt nur den Höhenunterschied zu prüfen, können wir Folgendes tun View v = this.getCurrentFocus();if (diff>100 && v != null){ // Its keyboard } else { //Keyboard hidden }

698voto

Reuben Scratton Punkte 38292

NEUE ANTWORT hinzugefügt am 25. Januar 2012

Seit ich die folgende Antwort geschrieben habe, hat mich jemand auf die Existenz von ViewTreeObserver und Freunde, APIs, die seit Version 1 im SDK schlummern.

Anstatt einen benutzerdefinierten Layout-Typ zu benötigen, besteht eine viel einfachere Lösung darin, der Root-Ansicht Ihrer Aktivität eine bekannte ID zu geben, etwa @+id/activityRoot Hängen Sie einen GlobalLayoutListener in den ViewTreeObserver ein, und berechnen Sie von dort aus den Größenunterschied zwischen dem View Root Ihrer Aktivität und der Fenstergröße:

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 Sie ein Dienstprogramm wie:

public static float dpToPx(Context context, float valueInDp) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}

Vorsicht!

Nota: Ihre Anwendung muss dieses Flag im Android Manifest setzen android:windowSoftInputMode="adjustResize" Andernfalls wird die obige Lösung nicht funktionieren.

ORIGINALANTWORT

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), dann passe ich meine Top-Level-Layout-Klasse in eine Klasse an, die Folgendes überschreibt onMeasure() . Die grundlegende Logik ist, dass, wenn das Layout deutlich weniger als die Gesamtfläche des Fensters ausfüllt, wahrscheinlich eine weiche Tastatur angezeigt wird.

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 Activity-Klasse...

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
    }

    ...
}

63 Stimmen

Dies funktionierte bei mir nicht, bis ich feststellte, dass Sie das folgende Attribut für Ihre Aktivität festlegen müssen: Android:windowSoftInputMode="adjustResize"

0 Stimmen

Ich kann nicht die Besetzung zu LinearLayoutThatDetectsSoftKeyboard von meinem LinearLayout tun

0 Stimmen

+1, aber was für eine Qual... (Ich verwende die Prüfung in einem Funktionstest)

311voto

Kachi Punkte 3579

Hoffentlich hilft das jemandem weiter.

Die neue Antwort, die Reuben Scratton gegeben hat, ist großartig und wirklich effizient, aber sie funktioniert wirklich nur, wenn Sie Ihren windowSoftInputMode auf adjustResize setzen. Wenn Sie es auf adjustPan einstellen, ist es immer noch nicht möglich zu erkennen, ob die Tastatur sichtbar ist oder nicht, indem Sie seinen Code-Schnipsel verwenden. Um dies zu umgehen, habe ich diese kleine Ä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.height();
    if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
        ... do something here
    }
 }
});

1 Stimmen

Das hat bei mir funktioniert. Ich habe versucht, den Tastaturstatus von einem benutzerdefinierten TwoDScrollerView ähnlich wie stackoverflow.com/a/5224088/530513 allerdings auch mit Zoomen. Das Kind war nicht einfach ein ImageView sondern ein benutzerdefiniertes Layout (erweitert RelativeLayout ), konnte aber die Tastatur mit der empfohlenen Lösung nicht erkennen, obwohl die Einstellung android:windowSoftInputMode="adjustResize" . Danke!

1 Stimmen

Danke, danke, danke! adjustResize ist für meine Anwendung einfach nicht praktikabel und Ihre Lösung hat perfekt funktioniert.

1 Stimmen

Arbeitet mit ActionBar y ActionBarSherlock . Herzlichen Dank! Übrigens, es gibt eine Methode r.height() :)

57voto

TacB0sS Punkte 9806

Es ist eine Ewigkeit her, was den Computer betrifft, aber diese Frage ist immer noch unglaublich aktuell!

Ich habe also die obigen Antworten genommen und sie ein wenig 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 die DefaultKeyboardDP nicht auf Ihr Gerät passt, spielen Sie mit dem Wert und posten Sie einen Kommentar, damit alle wissen, wie hoch der Wert sein sollte... schließlich werden wir den richtigen Wert bekommen, der auf alle Geräte passt!

Weitere Einzelheiten finden Sie auf der Website Cyborg

2 Stimmen

+1 Vielen Dank!! Ich habe die anderen Antworten ausprobiert, aber sie haben nicht funktioniert. Dann habe ich Ihre gefunden und es funktioniert wie ein Zauber. Toller Code! :D

0 Stimmen

Dies funktioniert nur, wenn Sie hinzufügen: Android:windowSoftInputMode="stateHidden|adjustPan" oder Android:windowSoftInputMode="stateHidden|adjustResize" Danke !!!!

0 Stimmen

Sind Sie sicher? Wenn Speicher-Server, bekam ich die Ereignisse richtig auch, wenn die Android:windowSoftInputMode seinen Standardwert hatte... das einzige, was nicht funktionierte, ist das Verhalten des Bildschirms, so dass ich es manuell schrumpfen...

51voto

Artem Zinnatullin Punkte 4146

Entschuldigen Sie die späte Antwort, aber ich hatte eine kleine Hilfsklasse erstellt, um Öffnungs-/Schließungsereignisse mit benachrichtigenden Zuhörern und anderen nützlichen Dingen zu behandeln, vielleicht findet sie jemand hilfreich:

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();
            }
        }
    }
}

Beispiel für die Verwendung:

final SoftKeyboardStateWatcher softKeyboardStateWatcher 
    = new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);

// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks

2 Stimmen

Die Klasse ist nicht klein, aber die Implementierung ist es sicherlich :). Danke, ich werde es versuchen :)

1 Stimmen

Schicken Sie mir eine Nachricht, wenn Sie Probleme damit haben :) Ich habe es erfolgreich in 2 Projekten verwendet

0 Stimmen

Nachdem ich viele Beispiele ausprobiert hatte und auf kleinere Probleme gestoßen war, war dies dasjenige, das für mich auf vielen verschiedenen Geräten (einschließlich xxhdpi) am besten funktionierte. Plus es ist in seinem eigenen netten wiederverwendbare Klasse. Ich konvertierte es über in mono droid verwendet werden.

35voto

Orchard Cafe Punkte 359

Einige Verbesserungen, um zu verhindern, dass die Sichtbarkeit der Soft-Tastatur auf Geräten mit hoher Dichte falsch erkannt wird:

  1. Der Schwellenwert für den Höhenunterschied sollte wie folgt definiert werden 128 dp pas 128 Pixel .
    Siehe Google Design Doc über Metriken und Raster , 48 dp ist eine angenehme Größe für das zu berührende Objekt und 32 dp ist das Minimum für Tasten. Generische Soft-Tastatur sollte 4 Reihen von Tasten umfassen, so dass die Mindesthöhe der Tastatur sein sollte: 32 dp * 4 = 128 dp Das bedeutet, dass die Schwellenwertgröße durch Multiplikation der Gerätedichte in Pixel übertragen werden sollte. Für xxxhdpi-Geräte (Dichte 4) sollte die Soft-Tastatur-Höhenschwelle 128 * 4 = 512 Pixel betragen.

  2. Höhenunterschied zwischen der Wurzelansicht und ihrem sichtbaren Bereich:
    Höhe der Wurzelansicht - Höhe der Statusleiste - Höhe des sichtbaren Rahmens = Unterkante der Wurzelansicht - Unterkante des sichtbaren Rahmens, da die Höhe der Statusleiste gleich der Oberkante des sichtbaren Rahmens der Wurzelansicht ist.

    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;
    }

4 Stimmen

Dies sollte die akzeptierte Antwort sein. Wenn ich die Dichte ignoriere, erhalte ich sehr unterschiedliche Ergebnisse bei Geräten mit unterschiedlichen Formfaktoren, aber ähnlichen Pixelgrößen. Danke!

2 Stimmen

Danke...das ist ein besserer Zustand!

1 Stimmen

Ausgezeichnet. Die Methode isKeyboardShown() ist das, was wir brauchen. Danke

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X