我需要做一件非常简单的事情-找出软件键盘是否显示。这在Android中可行吗?


当前回答

抱歉回答晚了,但我已经创建了一个小的帮助类来处理打开/关闭事件,通知侦听器和其他有用的东西,可能有人会发现它有帮助:

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

使用的例子:

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

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

其他回答

我知道如何准确地确定键盘是否隐藏。

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

这适用于平板电脑。当导航栏水平显示时。

不要编写任何硬代码。最好的方法是,你必须调整你的视图,而Get Focus on EditText与键盘显示。 您可以使用下面的代码将活动上的resize属性添加到清单文件中。

android: windowSoftInputMode = adjustResize”

在使用上述大多数建议添加固定数字的解决方案时,我刚刚遇到了一个错误。

S4的dpi很高,导致导航栏的高度为100px,因此我的应用程序认为键盘一直是打开的。

所以,随着所有新的高分辨率手机的发布,我认为使用硬编码值从长远来看不是一个好主意。

在各种屏幕和设备上进行测试后,我发现一个更好的方法是使用百分比。 获取decorView和你的应用内容之间的差异,然后检查这个差异的百分比。 从我得到的统计数据来看,大多数导航栏(无论大小、分辨率等)将占据屏幕的3%到5%。如果键盘是打开的,它会占据屏幕的47%到55%。

作为结论,我的解决方案是检查是否差异超过10%,然后我假设它的键盘打开。

Reuben Scratton的新答案(计算HeightDiff int HeightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();)如果您设置半透明状态栏模式,将无法在活动中工作。

如果你使用半透明状态栏,activityRootView.getHeight()将永远不会改变软键盘是否可见。它将始终返回活动和状态栏的高度。

例如,Nexus 4, Android 5.0.1,将Android:windowTranslucentStatus设置为true,它将永远返回1184,即使ime已经打开。如果你设置android:windowTranslucentStatus为false,它将正确返回高度,如果ime不可见,它将返回1134(不包括状态栏)。关闭ime,它可能会返回5xx(取决于ime的高度)

我不知道这是否是一个bug,我已经尝试了4.4.4和5.0.1,结果是一样的。

所以,到目前为止,第二个最被认可的答案,Kachi的解决方案将是最安全的方法来计算ime的高度。以下是一份复印件:

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

InputMethodManager有关于软键盘的信息。你从一个活动中获得它:

((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))

你可以摆弄一下,看看它能告诉你什么。你可以用它来显示或隐藏软输入…