it-swarm.com.de

So überprüfen Sie die Sichtbarkeit der Softwaretastatur in Android

Ich muss etwas sehr einfaches tun - herausfinden, ob die Software-Tastatur angezeigt wird. Ist das in Android möglich?

475
fhucho

NEUE ANTWORT _ ​​hinzugefügt am 25. Januar 2012

Seit dem Schreiben der folgenden Antwort hat mich jemand auf die Existenz von ViewTreeObserver und Freunden hingewiesen, APIs, die seit Version 1 im SDK lauern.

Anstatt einen benutzerdefinierten Layouttyp zu erfordern, ist es eine viel einfachere Lösung, der Root-Ansicht Ihrer Aktivität eine bekannte ID zuzuweisen, beispielsweise @+id/activityRoot, einen GlobalLayoutListener in den ViewTreeOb-Server einzuhaken und daraus den Größenunterschied zwischen dem View-Root 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 Android:windowSoftInputMode="adjustResize" setzen, da ansonsten die oben genannte Lösung nicht funktioniert.

ORIGINAL 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 wieder verschwindet (was häufig vorkommt), dann muss ich meine oberste Layoutklasse in eine anpassen, die onMeasure() überschreibt. Die grundlegende Logik ist, dass, wenn sich das Layout wesentlich weniger als die Gesamtfläche des Fensters füllt, eine Soft-Tastatur wahrscheinlich 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 deiner 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
    }

    ...
}
643
Reuben Scratton

Hoffentlich hilft das jemandem.

Die neue Antwort, die Reuben Scratton gab, ist großartig und sehr effizient, aber sie funktioniert wirklich nur, wenn Sie den windowSoftInputMode auf adjustResize einstellen. Wenn Sie "adjustPan" einstellen, kann mit seinem Code-Snippet immer noch nicht erkannt werden, ob die Tastatur sichtbar ist. 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.bottom - r.top);
    if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
        ... do something here
    }
 }
}); 
291
Kachi

Tut mir leid für die späte Antwort, aber ich hatte eine kleine Hilfsklasse für das Öffnen/Schließen von Ereignissen mit Benachrichtigungs-Listenern und anderen nützlichen Dingen erstellt. 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();
            }
        }
    }
}

Verwendungsbeispiel:

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

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

Es war schon immer ein Computer, aber diese Frage ist immer noch unglaublich relevant!

Also habe ich 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 :)

NOTE: Wenn Sie feststellen, dass das DefaultKeyboardDP nicht auf Ihr Gerät passt, spielen Sie mit dem Wert und posten Sie einen Kommentar, damit jeder wissen kann, was der Wert sein sollte ... schließlich werden wir das richtige Ergebnis erhalten Wert für alle Geräte!

Weitere Informationen finden Sie in der Implementierung unter Cyborg .

50
TacB0sS

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

  1. Der Schwellenwert der Höhendifferenz sollte als 128 dp definiert werden, nicht als 128 Pixel.
    Siehe Google-Design-Dokument zu Metriken und Raster , 48 dp hat eine angenehme Größe für Berührungsobjekte und 32 dp ist für Schaltflächen mindestens. Die generische Soft-Tastatur sollte 4 Tastenreihen enthalten. Die minimale Tastaturhöhe sollte daher Folgendes betragen: 32 dp * 4 = 128 dp, dh, die Schwellenwertgröße sollte durch die multiplizierte Gerätedichte auf Pixel übertragen werden. Bei xxxhdpi-Geräten (Dichte 4) sollte der Schwellenwert für die Höhe der Soft-Tastatur 128 * 4 = 512 Pixel betragen.

  2. Höhenunterschied zwischen der Wurzelansicht und ihrem sichtbaren Bereich:
    Wurzelansicht Höhe - Statusleiste Höhe - sichtbare Rahmenhöhe = Wurzelansicht unten - sichtbarer Rahmen unten, da die Höhe der Statusleiste der oberen Ansicht der Wurzelansicht 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;
    }
    
31
Orchard Cafe

Ich habe ein wenig Zeit gebraucht, um das herauszufinden ... Ich habe ein paar CastExceptions ausgeführt, habe aber herausgefunden, dass Sie 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 "MasterPage in Android". Siehe den Link hier: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-Android.aspx

8

Das Überprüfen der Höhe von Elementen ist nicht zuverlässig, da einige Tastaturen wie WifiKeyboard die Höhe Null haben.

Sie können stattdessen das Rückrufergebnis von showSoftInput () und hideSoftInput () verwenden, um den Status der Tastatur zu überprüfen. Vollständige Details und Beispielcode bei

https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-Android

6
Roger Keays

Wenn Sie Ihre Tastatur ausblenden und gleichzeitig den Soft-Input-Status überprüfen möchten, 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.

5

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

Ich fand, dass eine Kombination aus @ Reuben_Scrattons Methode und @ Yogeshs Methode am besten zu funktionieren scheint. Die Kombination ihrer Methoden würde so etwas 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
    }
  }
});
3
cbradley

Es gibt eine versteckte Methode, die dazu beitragen 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()
  }
}
3
Kevin Du

Es gibt auch eine Lösung mit Systeminsets, die jedoch nur mit API >= 21 (Android L) funktioniert. Angenommen, Sie haben BottomNavigationView, das ein Kind von LinearLayout ist, und Sie müssen es ausblenden, wenn die Tastatur angezeigt wird:

> LinearLayout
  > ContentView
  > BottomNavigationView

Alles, was Sie tun müssen, ist, LinearLayout so zu erweitern:

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, wenn Tastatur angezeigt wird, die Systemeinfügungen mit einem ziemlich großen .bottom-Wert geändert werden.

3
nikis

Sie können das Hide der Softkeyboards mit decorView von activity 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);
    }
}
3
Zebulon Li

Ich habe eine kleine Variante der Antwort von Reuban verwendet, die sich unter bestimmten Umständen als hilfreich erwiesen hat, insbesondere bei Geräten mit hoher Auflösung. 

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
                }
            }
        });
2
PearsonArtPhoto

Keine dieser Lösungen funktioniert für Lollipop so, wie sie ist. In Lollipop schließt activityRootView.getRootView().getHeight() die Höhe der Schaltflächenleiste ein, während die Ansicht die Ansicht nicht misst. Ich habe die beste/einfachste Lösung für 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
    }
  }
});
2
nathanielwolf

Es war schon immer für den Computer, aber diese Frage ist immer noch unglaublich relevant! Also habe ich 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 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.

2
Roselyn Soffer

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 ... \\
        }
    }
});
1
Ofek Ashery

Beim Ändern der Ausrichtung von Fragmenten innerhalb eines Viewpagers hatte ich Schwierigkeiten, den Tastaturstatus beizubehalten. Ich bin mir nicht sicher warum, aber es scheint nur unklar zu sein und verhält sich anders als eine Standardaktivität.

Um den Tastaturstatus in diesem Fall beizubehalten, sollten Sie zunächst Android:windowSoftInputMode = "stateUnchanged" zu Ihrem AndroidManifest.xml hinzufügen. Möglicherweise stellen Sie jedoch fest, dass dadurch nicht das gesamte Problem gelöst wird. Die Tastatur konnte für mich nicht geöffnet werden, wenn sie zuvor vor dem Orientierungswechsel 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 ... Die sauberste, die ich gefunden habe, war George Maisuradze - verwenden Sie den booleschen Callback 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 onCreate abgerufen. Dann zeigte ich die Tastatur gewaltsam in onCreateView, wenn sie den Wert true hatte (es gibt true zurück, wenn die Tastatur sichtbar ist, bevor sie vor der Zerstörung des Fragments tatsächlich ausgeblendet wird).

1
Quantum Dot

Ich habe gerade einen Fehler gefunden, als ich die meisten der oben genannten Lösungen verwendete, die das Hinzufügen einer festen Zahl vorschlagen.

S4 hat eine hohe Auflösung, was dazu führt, dass die Höhe der Navigationsleiste 100px beträgt. Daher ist meine App der Meinung, dass die Tastatur immer geöffnet ist.

Da alle neuen hochauflösenden Telefone auf den Markt kommen, glaube ich, dass die Verwendung eines hart codierten Werts keine langfristige Idee ist.

Ein besserer Ansatz, den ich nach einigen Tests auf verschiedenen Bildschirmen und Geräten gefunden hatte, war die Verwendung des Prozentsatzes Ermitteln Sie die Differenz zwischen decorView und Ihrem App-Inhalt und prüfen Sie anschließend, wie viel Prozent dieser Differenz ausmachen. Die meisten Navigationsleisten (unabhängig von Größe, Auflösung usw.) der angezeigten Statistiken belegen zwischen 3% und 5% des Bildschirms. Wenn die Tastatur offen ist, nimmt sie zwischen 47% und 55% des Bildschirms ein.

Als Schlussfolgerung bestand meine Lösung darin, zu prüfen, ob der Unterschied mehr als 10% beträgt. Dann gehe ich davon aus, dass die Tastatur geöffnet ist.

1
N Jay

Meine Antwort ist im Grunde die gleiche wie die von Kachi, aber ich habe sie in eine Nice-Helper-Klasse gepackt, um die Art und Weise, wie sie in meiner App verwendet wird, zu bereinigen.

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 dienen nur der Bequemlichkeit

1
billylindeman

sie können es versuchen, für mich großartig arbeiten:

InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

if (imm.isAcceptingText()) {
    //Software Keyboard was shown..
} else {
    //Software Keyboard was not shown..
}
1
IRvanFauziE

Die von Reuben Scratton und Kachi angebotene Lösung scheint sich auf die Pixeldichte der Geräte zu verlassen. Wenn Sie ein Gerät mit hoher Dichte haben, kann der Höhenunterschied auch bei heruntergesetzter Tastatur größer als 100 sein. Ein wenig Arbeit wäre, den ursprünglichen Höhenunterschied (mit gedrückter Tastatur) zu sehen und dann mit dem aktuellen Unterschied zu vergleichen.

boolean isOpened = false;
int firstHeightDiff = -1;

public void setListenerToRootView(){
    final View activityRootView = getActivity().getWindow().getDecorView().findViewById(Android.R.id.content);
    Rect r = new Rect();
    activityRootView.getWindowVisibleDisplayFrame(r);
    firstHeightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (isAdded()) {
                Rect r = new Rect();
                activityRootView.getWindowVisibleDisplayFrame(r);
                int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
                isOpened = heightDiff>firstHeightDiff+100;
                if (isAdded())
                    if(isOpened) {
                        //TODO stuff for when it is up
                    } else {
                        //TODO stuf for when it is down
                    }
            }
        }
    });
}
0
ericmguimaraes

Denken hat einen einfachen Weg, wie folgt:

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.isActive();

Sie können auch sehen, ob er in einer bestimmten Ansicht aktiv ist:

imm.isActive(View v);
0
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 zwei erforderlichen Methoden.

Definieren Sie zunächst die bearbeitbare Fensterhöhe 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 in 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!

0
Belboz

Eine Methode, die keinen LayoutListener benötigt

In meinem Fall möchte ich den Status der Tastatur vor dem Ersetzen meines Fragments speichern. Ich rufe die Methode hideSoftInputFromWindow von onSaveInstanceState auf, 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.

0
Gordak

Dieser Code funktioniert super Nizza

verwenden Sie diese Klasse für die Root-Ansicht:

public class KeyboardConstraintLayout extends ConstraintLayout {

private KeyboardListener keyboardListener;
private EditText targetEditText;
private int minKeyboardHeight;
private boolean isShow;

public KeyboardConstraintLayout(Context context) {
    super(context);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (!isInEditMode()) {
        Activity activity = (Activity) getContext();
        @SuppressLint("DrawAllocation")
        Rect rect = new Rect();
        getWindowVisibleDisplayFrame(rect);

        int statusBarHeight = rect.top;
        int keyboardHeight = activity.getWindowManager().getDefaultDisplay().getHeight() - (rect.bottom - rect.top) - statusBarHeight;

        if (keyboardListener != null && targetEditText != null && targetEditText.isFocused()) {
            if (keyboardHeight > minKeyboardHeight) {
                if (!isShow) {
                    isShow = true;
                    keyboardListener.onKeyboardVisibility(true);
                }
            }else {
                if (isShow) {
                    isShow = false;
                    keyboardListener.onKeyboardVisibility(false);
                }
            }
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

public boolean isShowKeyboard() {
    return isShow;
}

public void setKeyboardListener(EditText targetEditText, KeyboardListener keyboardListener) {
    this.targetEditText = targetEditText;
    this.keyboardListener = keyboardListener;
}

public interface KeyboardListener {
    void onKeyboardVisibility (boolean isVisible);
}

}

und setzen Sie den Tastaturlistener in Aktivität oder Fragment:

    rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
    @Override
    public void onKeyboardVisibility(boolean isVisible) {

    }
});
0
saleh gholamian

Die neue Antwort von Reuben Scratton (Berechnen der HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();) funktioniert nicht, wenn Sie den durchscheinenden Statusleistenmodus einstellen.

wenn Sie eine durchscheinende Statusleiste verwenden, ändert activityRootView.getHeight() niemals das Wetter, wenn die Softtastatur sichtbar ist. Es wird immer die Höhe der Aktivitäts- und Statusleiste angezeigt.

Wenn Sie beispielsweise Nexus 4, Android 5.0.1, Android:windowTranslucentStatus auf true setzen, wird der Wert 1184 für immer zurückgegeben, auch wenn das ime geöffnet ist. Wenn Sie Android:windowTranslucentStatus auf false setzen, wird Height korrekt zurückgegeben. Wenn Sie unsichtbar sind, wird 1134 zurückgegeben (die Statusleiste nicht eingeschlossen). Schließen Sie das IME. Es wird möglicherweise 5xx zurückgegeben (abhängig von der Höhe des Images).

Ich weiß nicht, ob dies ein Fehler ist, ich habe es mit 4.4.4 und 5.0.1 versucht, das Ergebnis ist dasselbe.

Bis jetzt ist Kachis Lösung die zweitmeistigste Antwort, die sicherste Methode, um die Höhe des Systems 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
    }
 }
}); 
0
Loyea

Nachdem ich einige Probleme mit unterschiedlichen Auflösungen verstanden hatte, entschied ich mich für eine relative Größe. Wie ich feststellte, beträgt der Unterschied zwischen sichtbaren und verborgenen Zuständen etwa 30%. Also entschied ich mich, 128 PX durch 0,3 zu ersetzen.

Und ich habe diesen Klassenlistener hinzugefügt, um über Änderungen zu informieren.

Hier ist meine Version

import Android.app.*;
import Android.graphics.*;
import Android.view.*;

public class SoftKeyboardState {
  public static final int HIDDEN = 0, VISIBLE = 1;
  private OnKeyboardStateChangedListener listener;
  private View decorView;

  public SoftKeyboardState(Activity activity) {
    this.decorView = activity.findViewById(Android.R.id.content);
    initKeyboardListener();
  }

  private void initKeyboardListener() {
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(
      new ViewTreeObserver.OnGlobalLayoutListener(){
        private final Rect windowVisibleDisplayFrame = new Rect();
        private int lastVisibleDecorViewHeight;

        @Override
        public void onGlobalLayout() {
          decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
          final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();

          if (lastVisibleDecorViewHeight != 0) {
            if ((lastVisibleDecorViewHeight > visibleDecorViewHeight) && (lastVisibleDecorViewHeight / visibleDecorViewHeight >= 0.3f)) {
              // visible
              if (listener != null)listener.onKeyboardStateChanged(VISIBLE);
            } else if ((lastVisibleDecorViewHeight < visibleDecorViewHeight) && (visibleDecorViewHeight / lastVisibleDecorViewHeight >= 0.3f)) {
              // hidden
              if (listener != null)listener.onKeyboardStateChanged(HIDDEN);
            }
          }
          lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
      });
  }

  public void setOnKeyboardStateChangedListener(OnKeyboardStateChangedListener listener) {
    this.listener = listener;
  }

  public interface OnKeyboardStateChangedListener {
    public void onKeyboardStateChanged(int state);
  }
}
0

Ich weiß, dass dies ein alter Beitrag ist, aber ich denke, dass dies der einfachste Ansatz ist, den ich kenne, und mein Testgerät ist Nexus 5. Ich habe es nicht mit anderen Geräten versucht. Hoffe, dass andere ihre Vorgehensweise teilen, wenn sie meinen Code als nicht gut empfinden :)

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,

0
Fran Ceriu

Ich weiß, wie genau Sie feststellen können, ob die Tastatur verborgen 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.

0

Machen Sie keinen harten Code. Am besten müssen Sie die Größe der Ansichten ändern, während Sie Get Key in EditText mit KeyBord Show ... abrufen. Sie können die Eigenschaft zur Größenänderung für die Aktivität in die Manifest-Datei einfügen, indem Sie den folgenden Code verwenden.

Android:windowSoftInputMode="adjustResize"

0
Rahul Mandaliya

Hier ist meine Lösung und es funktioniert. Statt nach der Pixelgröße zu suchen, überprüfen Sie, 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();
}
0
Meanman

Es gibt eine direkte Methode, dies herauszufinden. Außerdem sind keine Layoutänderungen erforderlich.
Es funktioniert also auch im immersiven Vollbildmodus.

Der Trick ist, dass Sie versuchen, die Soft-Tastatur ein- oder auszublenden und das Ergebnis dieses Versuchs zu erfassen.
Keine Panik, die Tastatur wird nicht wirklich angezeigt oder ausgeblendet. Wir fragen nur nach dem Staat.

Um auf dem neuesten Stand zu bleiben, können Sie den Vorgang einfach wiederholen, z. alle 200 Millisekunden mit einem Handler.

Eine Implementierung finden Sie hier: https://stackoverflow.com/a/27567074/2525452

0
fies

Hier ist eine Problemumgehung, um zu wissen, ob das Softkeyboard angezeigt wird.

  1. Prüfen Sie, ob auf dem System laufende Dienste ausgeführt werden. Verwenden Sie dazu ActivityManager.getRunningServices (max_count_of_services);
  2. Überprüfen Sie in den zurückgegebenen ActivityManager.RunningServiceInfo-Instanzen den Wert clientCount für den Softkey-Tastaturdienst.
  3. Der oben genannte ClientCount wird jedes Mal inkrementiert, die Soft-Tastatur wird angezeigt. Wenn clientCount zum Beispiel ___ war, wäre dies 1, wenn die Tastatur angezeigt wird.
  4. Bei einer Tastaturkündigung wird clientCount dekrementiert. In diesem Fall wird es auf 1 zurückgesetzt.

Einige der beliebtesten Tastaturen enthalten bestimmte Schlüsselwörter in ihren Klassennamen:

Google AOSP = IME
Swype = IME
Swiftkey = KeyboardService
Fleksy = keyboard
Adaptxt = IME (KPTAdaptxtIME)
Smart = Keyboard (SmartKeyboard)

Suchen Sie in ActivityManager.RunningServiceInfo nach den oben genannten Mustern in ClassNames. Auch clientPackage = Android von ActivityManager.RunningServiceInfo gibt an, dass die Tastatur an das System gebunden ist.

Die oben genannten Informationen können kombiniert werden, um auf strikte Weise herauszufinden, ob die Soft-Tastatur sichtbar ist.

0
Satishkumar

Vielleicht hilft Ihnen das:

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

ich denke, diese Methode wird Ihnen helfen herauszufinden, ob die Tastatur 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;
    }

}
0
John smith