304

Android中有没有办法检测软件(又名“软”)键盘是否在屏幕上可见?

4

34 回答 34

309

这对我有用。也许这始终是所有版本的最佳方式。

由于 onGlobalLayout 方法多次调用,因此设置键盘可见性属性并延迟观察此更改将是有效的。检查设备旋转也很好,windowSoftInputMode不是adjustNothing

boolean isKeyboardShowing = false;
void onKeyboardVisibilityChanged(boolean opened) {
    print("keyboard " + opened);
}

// ContentView is the root view of the layout of this activity/fragment    
contentView.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {

        Rect r = new Rect();
        contentView.getWindowVisibleDisplayFrame(r);
        int screenHeight = contentView.getRootView().getHeight();

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        int keypadHeight = screenHeight - r.bottom;

        Log.d(TAG, "keypadHeight = " + keypadHeight);

        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true
                onKeyboardVisibilityChanged(true)
            }
        }
        else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false
                onKeyboardVisibilityChanged(false)
            }
        }
    }
});
于 2014-11-17T01:06:17.373 回答
79

试试这个:

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

    if (imm.isAcceptingText()) {
        writeToLog("Software Keyboard was shown");
    } else {
        writeToLog("Software Keyboard was not shown");
    }
于 2011-09-23T14:10:30.333 回答
75

没有直接的方法 - 请参阅http://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898a来自 Android 团队的 Dianne Hackborn 已回复。但是,您可以通过检查#onMeasure 中的窗口大小是否更改来间接检测到它。请参阅如何检查 Android 中软件键盘的可见性?.

于 2011-05-25T22:29:54.677 回答
73

我创建了一个可用于此的简单类:https ://github.com/ravindu1024/android-keyboardlistener 。只需将其复制到您的项目中并按如下方式使用:

KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
    @Override
    public void onToggleSoftKeyboard(boolean isVisible)
    {
        Log.d("keyboard", "keyboard visible: "+isVisible);
    }
});
于 2016-07-15T02:37:01.523 回答
32

好简单

1. 把 id 放在你的根视图上

rootView在这种情况下只是一个指向我的根视图的视图 a relative layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/addresses_confirm_root_view"
                android:background="@color/WHITE_CLR">

2. 在你的 Activity 中初始化你的根视图:

RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);

3.通过使用检测键盘是打开还是关闭getViewTreeObserver()

    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
                
                if (heightDiff > 100) { // Value should be less than keyboard's height 
                    Log.e("MyActivity", "keyboard opened");
                } else { 
                    Log.e("MyActivity", "keyboard closed");
                }
            }
        });
于 2016-02-11T19:11:37.470 回答
26

使用androidx 核心版本 1.5.0-alpha02中的新功能WindowInsetsCompat,您可以轻松检查软键盘的可见性,如下所示

引用reddit评论

val View.keyboardIsVisible: Boolean
    get() = WindowInsetsCompat
        .toWindowInsetsCompat(rootWindowInsets)
        .isVisible(WindowInsetsCompat.Type.ime())

关于向后兼容性的一些说明,引用自发行说明

新功能

WindowInsetsCompatAPI 已更新为 Android 11 平台中的API。这包括新的ime()插入类型,它允许检查屏幕键盘的可见性和大小。

关于类型的一些注意事项,当您的 Activity 使用窗口软输入模式ime()时,它在 API 23+ 上非常可靠。adjustResize如果您改用该adjustPan模式,它应该可以可靠地返回到 API 14。

参考

于 2020-08-21T06:36:30.930 回答
13

因此,在长时间使用 AccessibilityServices、窗口插图、屏幕高度检测等之后,我想我找到了一种方法。

免责声明:它使用 Android 中的隐藏方法,这意味着它可能不一致。但是,在我的测试中,它似乎有效。

该方法是InputMethodManager#getInputMethodWindowVisibleHeight(),从 Lollipop (5.0) 开始就存在。

调用返回当前键盘的高度(以像素为单位)。理论上,键盘不应该是 0 像素高,所以我做了一个简单的高度检查(在 Kotlin 中):

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
    //keyboard is shown
else {
    //keyboard is hidden
}

当我调用隐藏方法时,我使用Android Hidden API来避免反射(我为我开发的应用程序做了很多,这些应用程序主要是 hacky/tuner 应用程序),但这也应该可以通过反射实现:

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic
于 2018-09-04T18:09:19.467 回答
8

我以此为基础:https ://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android

/**
* To capture the result of IMM hide/show soft keyboard
*/
public class IMMResult extends ResultReceiver {
     public int result = -1;
     public IMMResult() {
         super(null);
}

@Override 
public void onReceiveResult(int r, Bundle data) {
    result = r;
}

// poll result value for up to 500 milliseconds
public int getResult() {
    try {
        int sleep = 0;
        while (result == -1 && sleep < 500) {
            Thread.sleep(100);
            sleep += 100;
        }
    } catch (InterruptedException e) {
        Log.e("IMMResult", e.getMessage());
    }
    return result;
}
}

然后写了这个方法:

public boolean isSoftKeyboardShown(InputMethodManager imm, View v) {
    
    IMMResult result = new IMMResult();
    int res;
    
    imm.showSoftInput(v, 0, result);

    // if keyboard doesn't change, handle the keypress
    res = result.getResult();
    if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
            res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {

        return true;
    }
    else
        return false;

}

然后,您可以使用它来测试可能已打开软键盘的所有字段(EditText、AutoCompleteTextView 等):

    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1))
        //close the softkeyboard
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

Addmittely 不是一个理想的解决方案,但它可以完成工作。

于 2015-06-27T15:38:46.307 回答
8

您可以使用来自androidx.core (version 1.5.0-rc01) 的 WindowInsetsCompat。此代码适用于API 21及更高版本。Kotlin 代码示例:

ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets ->
    val isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
    if (isKeyboardVisible) {
    }
}

root是您的 Activity 的根视图。

更新

今天我正在寻找如何检测键盘可见性。起初,此代码不起作用。所以我不得不:

  1. 添加android:windowSoftInputMode="adjustResize"到我的 AndroidManifest.xml 文件中:
xml
        <activity android:name="com.soumicslabs.activitykt.StartActivity"
            android:theme="@style/AccountKitTheme.Default"
          android:configChanges="orientation|screenSize"
          android:screenOrientation="portrait"
          android:windowSoftInputMode="adjustResize"
          />
  1. 在您的活动中, set WindowCompat.setDecorFitsSystemWindows(window, false),这告诉 android 我们想要手动处理事情/不想使用系统默认值:
        val window = this.window
        WindowCompat.setDecorFitsSystemWindows(window, false)  // <-- this tells android not to use system defaults, so we have to setup quite a lot of behaviors manually
  1. 最后,设置你onApplyWindowInsetsListener
val callBack = OnApplyWindowInsetsListener { view, insets ->
            val imeHeight = insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom?:0
            Log.e("tag", "onKeyboardOpenOrClose imeHeight = $imeHeight")
// todo: logic
val isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
    if (isKeyboardVisible) {
       // do something
    }else{
        // do something else
    }
    insets?: WindowInsetsCompat(null)
  }

ViewCompat.setOnApplyWindowInsetsListener(mainContainer, callBack)

这对我有用。

于 2021-03-25T18:14:56.520 回答
7

您可以使用 showSoftInput() 和 hideSoftInput() 的回调结果来检查键盘的状态。完整的细节和示例代码在

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

于 2012-02-20T23:45:04.060 回答
6

您可以参考这个答案 - https://stackoverflow.com/a/24105062/3629912

它每次都对我有用。

adb shell dumpsys window InputMethod | grep "mHasSurface"

如果软件键盘可见,它将返回 true。

于 2014-09-11T07:50:23.437 回答
6

对于我需要的要求,这要简单得多。希望这可能会有所帮助:

在 MainActivity 上:

public void dismissKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
    mKeyboardStatus = false;
}

public void showKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    mKeyboardStatus = true;
}

private boolean isKeyboardActive(){
    return mKeyboardStatus;
}

mKeyboardStatus 的默认原始布尔值将被初始化为false

然后按如下方式检查该值,并在必要时执行操作:

 mSearchBox.requestFocus();
    if(!isKeyboardActive()){
        showKeyboard();
    }else{
        dismissKeyboard();
    }
于 2015-08-26T18:25:07.543 回答
5

如果您需要检查键盘状态,这应该可以工作:

fun Activity.isKeyboardOpened(): Boolean {
    val r = Rect()

    val activityRoot = getActivityRoot()
    val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)

    activityRoot.getWindowVisibleDisplayFrame(r)

    val heightDiff = activityRoot.rootView.height - r.height()

    return heightDiff > visibleThreshold;
}

fun Activity.getActivityRoot(): View {
    return (findViewById<ViewGroup>(android.R.id.content)).getChildAt(0);
}

其中UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP= 100 和 dip() 是转换 dpToPx 的 anko func:

fun dip(value: Int): Int {
    return (value * Resources.getSystem().displayMetrics.density).toInt()
}
于 2018-11-23T11:19:55.630 回答
5

现在终于有了从基于 Kotlin 的 Android R 开始的直接方法。

 val imeInsets = requireView().rootWindowInsets.isVisible(WindowsInsetsCompat.Type.ime()) 
    if (imeInsets) { 
     //Ime is visible
     //Lets move our view by the height of the IME
     view.translationX = imeInsets.bottom }
于 2020-02-21T04:21:45.613 回答
4

我通过设置 GlobalLayoutListener 来做到这一点,如下所示:

final View activityRootView = findViewById(R.id.activityRoot);
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
                }
            }
        });
于 2014-02-21T21:59:09.267 回答
3

试试这个代码,如果 KeyboardShown 是 Shown 的话,它真的很有效,然后这个函数返回真值....

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;
}
于 2015-06-11T14:25:53.093 回答
2

就我而言,我的布局中只有一个EditText要管理,所以我想出了这个解决方案。它工作得很好,基本上它是一种自定义EditText,如果焦点发生变化或按下后退/完成按钮,它会监听焦点并发送本地广播。为了工作,您需要View在布局中放置一个虚拟对象android:focusable="true"android:focusableInTouchMode="true"因为当您调用焦点时clearFocus(),焦点将被重新分配给第一个可聚焦视图。虚拟视图示例:

<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>

附加信息

检测布局变化差异的解决方案效果不佳,因为它在很大程度上取决于屏幕密度,因为 100px 在某些设备中可能很多,而在其他一些设备中则不会出现误报。不同的供应商也有不同的键盘。

于 2015-09-30T11:53:59.913 回答
2

根据@bohdan-oliynyk 的回答,更紧凑的 Kotlin 版本

private const val KEYBOARD_VISIBLE_THRESHOLD_DP = 100

fun Activity.isKeyboardOpen(): Boolean {
    fun convertDpToPx(value: Int): Int =
        (value * Resources.getSystem().displayMetrics.density).toInt()

    val rootView = findViewById<View>(android.R.id.content)
    val visibleThreshold = Rect()
    rootView.getWindowVisibleDisplayFrame(visibleThreshold)
    val heightDiff = rootView.height - visibleThreshold.height()

    val accessibleValue = convertDpToPx(KEYBOARD_VISIBLE_THRESHOLD_DP)

    return heightDiff > accessibleValue
}

fun Activity.isKeyboardClosed(): Boolean {
    return isKeyboardOpen().not()
}
于 2020-08-26T12:33:43.920 回答
1

在 Android 中,您可以通过 ADB shell 进行检测。我编写并使用了这种方法:

{
        JSch jsch = new JSch();
        try {
            Session session = jsch.getSession("<userName>", "<IP>", 22);
            session.setPassword("<Password>");
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();

            ChannelExec channel = (ChannelExec)session.openChannel("exec");
            BufferedReader in = new BufferedReader(new    
            InputStreamReader(channel.getInputStream()));
            channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window 
            InputMethod | findstr \"mHasSurface\"");
            channel.connect();

            String msg = null;
            String msg2 = " mHasSurface=true";

            while ((msg = in.readLine()) != null) {
                Boolean isContain = msg.contains(msg2);
                log.info(isContain);
                if (isContain){
                    log.info("Hiding keyboard...");
                    driver.hideKeyboard();
                }
                else {
                    log.info("No need to hide keyboard.");
                }
            }

            channel.disconnect();
            session.disconnect();

        } catch (JSchException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
于 2015-08-03T11:44:40.750 回答
1
final View activityRootView = findViewById(R.id.rootlayout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            Rect r = new Rect();
            activityRootView.getWindowVisibleDisplayFrame(r);

            int screenHeight = activityRootView.getRootView().getHeight();
            Log.e("screenHeight", String.valueOf(screenHeight));
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.e("heightDiff", String.valueOf(heightDiff));
            boolean visible = heightDiff > screenHeight / 3;
            Log.e("visible", String.valueOf(visible));
            if (visible) {
                Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
            }
        }
});
于 2016-05-27T10:25:23.710 回答
1

@iWantScala 的答案很棒,但不为我工作
rootView.getRootView().getHeight()总是具有相同的价值

一种方法是定义两个变量

private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;

添加全局监听器

rootView.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            currentRootViewHeight = rootView.getHeight();
            if (currentRootViewHeight > maxRootViewHeight) {
                maxRootViewHeight = currentRootViewHeight;
            }
        }
    });

然后检查

if (currentRootViewHeight >= maxRootViewHeight) {
    // Keyboard is hidden
} else {
    // Keyboard is shown
}

工作正常

于 2017-08-19T15:54:48.997 回答
1

正如您可能知道的那样,只有在可能出现打字事件时,android 软件键盘才会可见。换句话说,只有在 EditText 获得焦点时,键盘才可见。这意味着您可以通过使用OnFocusChangeListener来获取键盘是否可见的天气。

//Declare this Globally

public boolean isKeyBoardVisible = false;

//In OnCreate *[For Activity]*, OnCreateView *[For Fragment]*

text_send.setOnFocusChangeListener(new View.OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus)
            isKeyBoardVisible = true;
        else
            isKeyBoardVisible = false;
    }
});

现在您可以在类中的任何位置使用isKeyBoardVisible变量来获取键盘是否打开的天气。它对我来说效果很好。

注意:当使用InputMethodManager以编程方式打开键盘时,此过程不起作用,因为这不会调用 OnFocusChangeListener。

于 2019-04-10T09:44:58.393 回答
0

我有一个类似的问题。我需要对屏幕上的 Enter 按钮(隐藏键盘)做出反应。在这种情况下,您可以订阅打开键盘的文本视图的 OnEditorAction - 如果您有多个可编辑框,则订阅所有这些框。

在您的 Activity 中,您可以完全控制键盘,因此如果您监听所有打开和关闭事件,无论键盘是否打开,您都不会遇到问题。

于 2011-01-25T16:39:23.027 回答
0

有一种直接的方法可以找到它。而且,它不需要更改布局。
所以它也可以在沉浸式全屏模式下工作。
但是,不幸的是,它不适用于所有设备。所以你必须用你的设备测试它。

诀窍是您尝试隐藏或显示软键盘并捕获该尝试的结果。
如果它工作正常,那么键盘并没有真正显示或隐藏。我们只要求状态。

为了保持最新,您只需使用处理程序重复此操作,例如每 200 毫秒。

下面的实现只做一次检查。
如果您进行多项检查,则应启用所有 (_keyboardVisible) 测试。

public interface OnKeyboardShowHide
{
    void    onShowKeyboard( Object param );
    void    onHideKeyboard( Object param );
}

private static Handler      _keyboardHandler    = new Handler();
private boolean             _keyboardVisible    = false;
private OnKeyboardShowHide  _keyboardCallback;
private Object              _keyboardCallbackParam;

public void start( OnKeyboardShowHide callback, Object callbackParam )
{
    _keyboardCallback      = callback;
    _keyboardCallbackParam = callbackParam;
    //
    View view = getCurrentFocus();
    if (view != null)
    {
        InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
        imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
    }
    else // if (_keyboardVisible)
    {
        _keyboardVisible = false;
        _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
    }
}

private ResultReceiver      _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
    @Override
    protected void onReceiveResult( int resultCode, Bundle resultData )
    {
        switch (resultCode)
        {
            case InputMethodManager.RESULT_SHOWN :
            case InputMethodManager.RESULT_UNCHANGED_SHOWN :
                // if (!_keyboardVisible)
                {
                    _keyboardVisible = true;
                    _keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
                }
                break;
            case InputMethodManager.RESULT_HIDDEN :
            case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
                // if (_keyboardVisible)
                {
                    _keyboardVisible = false;
                    _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
                }
                break;
        }
    }
};
于 2014-12-19T13:24:02.190 回答
0

这是了解软键盘是否可见的解决方法。

  1. 使用 ActivityManager.getRunningServices(max_count_of_services) 检查系统上正在运行的服务;
  2. 从返回的 ActivityManager.RunningServiceInfo 实例中,检查软键盘服务的clientCount值。
  3. 上述clientCount每次都会递增,显示软键盘。例如,如果 clientCount 最初为 1,则在显示键盘时它将为 2。
  4. 在键盘关闭时,clientCount 会递减。在这种情况下,它重置为 1。

一些流行的键盘在其类名中有某些关键字:

  1. 谷歌 AOSP = IME
  2. Swype = 输入法
  3. Swiftkey = 键盘服务
  4. Fleksy = 键盘
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. 智能 = 键盘 (SmartKeyboard)

从 ActivityManager.RunningServiceInfo,检查 ClassNames 中的上述模式。还有,ActivityManager.RunningServiceInfo的clientPackage =android,表示键盘是绑定系统的。

可以将上述信息结合起来,以一种严格的方式来确定软键盘是否可见。

于 2016-06-01T12:41:55.927 回答
0

我将答案转换为 kotlin,希望这对 kotlin 用户有所帮助。

private fun checkKeyboardVisibility() {
    var isKeyboardShowing = false

    binding.coordinator.viewTreeObserver.addOnGlobalLayoutListener {
        val r = Rect()
        binding.coordinator.getWindowVisibleDisplayFrame(r)
        val screenHeight = binding.coordinator.rootView.height

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        val keypadHeight = screenHeight - r.bottom


        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true

            }
        } else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false

            }
        }
    }
}
于 2019-06-16T06:56:03.363 回答
0

如果您在您的应用中支持 AndroidR 的 API,那么您可以使用以下方法。

In kotlin :
    var imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
        view.translationX = imeInsets.bottom 
    }

注意:这仅适用于 AndroidR 和以下 android 版本需要遵循其他一些答案,否则我会为此更新它。

于 2020-02-25T06:01:02.307 回答
0

它与活动的 adjustNothing 标志一起使用,并使用生命周期事件。还有 Kotlin:

/**
 * This class uses a PopupWindow to calculate the window height when the floating keyboard is opened and closed
 *
 * @param activity The parent activity
 *  The root activity that uses this KeyboardManager
 */
class KeyboardManager(private val activity: AppCompatActivity) : PopupWindow(activity), LifecycleObserver {

    private var observerList = mutableListOf<((keyboardTop: Int) -> Unit)>()

    /** The last value of keyboardTop */
    private var keyboardTop: Int = 0

    /** The view that is used to calculate the keyboard top  */
    private val popupView: View?

    /** The parent view  */
    private var parentView: View

    var isKeyboardShown = false
        private set

    /**
     * Create transparent view which will be stretched over to the full screen
     */
    private fun createFullScreenView(): View {
        val view = LinearLayout(activity)
        view.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT)
        view.background = ColorDrawable(Color.TRANSPARENT)
        return view
    }

    init {
        this.popupView = createFullScreenView()
        contentView = popupView

        softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE or LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
        inputMethodMode = INPUT_METHOD_NEEDED

        parentView = activity.findViewById(android.R.id.content)

        width = 0
        height = LayoutParams.MATCH_PARENT

        popupView.viewTreeObserver.addOnGlobalLayoutListener {
            val rect = Rect()
            popupView.getWindowVisibleDisplayFrame(rect)

            val keyboardTop = rect.bottom
            if (this.keyboardTop != keyboardTop) {
                isKeyboardShown = keyboardTop < this.keyboardTop
                this.keyboardTop = keyboardTop
                observerList.forEach { it(keyboardTop) }
            }
        }
        activity.lifecycle.addObserver(this)
    }

    /**
     * This must be called after the onResume of the Activity or inside view.post { } .
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun start() {
        parentView.post {
            if (!isShowing && parentView.windowToken != null) {
                setBackgroundDrawable(ColorDrawable(0))
                showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
            }
        }
    }

    /**
     * This manager will not be used anymore
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun close() {
        activity.lifecycle.removeObserver(this)
        observerList.clear()
        dismiss()
    }

    /**
     * Set the keyboard top observer. The observer will be notified when the keyboard top has changed.
     * For example when the keyboard is opened or closed
     *
     * @param observer The observer to be added to this provider
     */
    fun registerKeyboardTopObserver(observer: (keyboardTop: Int) -> Unit) {
        observerList.add(observer)
    }
}

使视图始终位于键盘上方的有用方法

fun KeyboardManager.updateBottomMarginIfKeyboardShown(
        view: View,
        activity: AppCompatActivity,
        // marginBottom of view when keyboard is hide
        marginBottomHideKeyboard: Int,
        // marginBottom of view when keybouard is shown
        marginBottomShowKeyboard: Int
) {
    registerKeyboardTopObserver { bottomKeyboard ->
        val bottomView = ViewUtils.getFullViewBounds(view).bottom
        val maxHeight = ScreenUtils.getFullScreenSize(activity.windowManager).y
        // Check that view is within the window size
        if (bottomView < maxHeight) {
            if (bottomKeyboard < bottomView) {
                ViewUtils.updateMargin(view, bottomMargin = bottomView - bottomKeyboard +
                        view.marginBottom + marginBottomShowKeyboard)
            } else ViewUtils.updateMargin(view, bottomMargin = marginBottomHideKeyboard)
        }
    }
}

在哪里 getFullViewBounds

fun getLocationOnScreen(view: View): Point {
    val location = IntArray(2)
    view.getLocationOnScreen(location)
    return Point(location[0], location[1])
}

fun getFullViewBounds(view: View): Rect {
     val location = getLocationOnScreen(view)
     return Rect(location.x, location.y, location.x + view.width,
            location.y + view.height)
 }

哪里得到FullScreenSize

fun getFullScreenSize(wm: WindowManager? = null) =
            getScreenSize(wm) { getRealSize(it) }

private fun getScreenSize(wm: WindowManager? = null, block: Display.(Point) -> Unit): Point {
    val windowManager = wm ?: App.INSTANCE.getSystemService(Context.WINDOW_SERVICE)
            as WindowManager
    val point = Point()
    windowManager.defaultDisplay.block(point)
    return point
}

哪里 updateMargin

fun updateMargin(
        view: View,
        leftMargin: Int? = null,
        topMargin: Int? = null,
        rightMargin: Int? = null,
        bottomMargin: Int? = null
) {
    val layoutParams = view.layoutParams as ViewGroup.MarginLayoutParams
    if (leftMargin != null) layoutParams.leftMargin = leftMargin
    if (topMargin != null) layoutParams.topMargin = topMargin
    if (rightMargin != null) layoutParams.rightMargin = rightMargin
    if (bottomMargin != null) layoutParams.bottomMargin = bottomMargin
    view.layoutParams = layoutParams
}
于 2020-03-20T07:35:23.297 回答
0

谢谢大家的回答,我根据自己的情况想办法

/**
 * Add global layout listener to observe system keyboard visibility
 */
private void initObserverForSystemKeyboardVisibility() {
    getRootView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //Add your own code here
            Log.d("TEST_CODE", "isSystemKeyboardVisible:" + isSystemKeyboardVisible())
        }
    });
}


/**
 * Check system keyboard visibility
 * @return true if visible
 */
public boolean isSystemKeyboardVisible() {
    try {
        final InputMethodManager manager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        final Method windowHeightMethod = InputMethodManager.class.getMethod("getInputMethodWindowVisibleHeight");
        final int height = (int) windowHeightMethod.invoke(manager);
        return height > 0;
    } catch (Exception e) {
        return false;
    }
}
于 2021-04-17T03:14:14.677 回答
0
private fun isKeyboardVisible(rootView: View) =
    ViewCompat.getRootWindowInsets(rootView)!!.isVisible(WindowInsetsCompat.Type.ime())
于 2021-10-15T17:11:51.293 回答
-1

我按如下方式执行此操作,但仅当您的目标是关闭/打开键盘时才重新启用。

关闭示例:(检查键盘是否已经关闭,如果没有 - 关闭)

imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
                    @Override
                    protected void onReceiveResult(int resultCode, Bundle resultData) {
                        super.onReceiveResult(resultCode, resultData);
                        if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
                            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    }
                });
于 2015-06-26T11:45:44.707 回答
-1

a 可能正在使用:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.d(
    getClass().getSimpleName(), 
    String.format("conf: %s", newConfig));

    if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
        onHardwareKeyboardChange(newConfig.hardKeyboardHidden);

        hardKeyboardHidden = newConfig.hardKeyboardHidden;
    }

    if (newConfig.keyboardHidden != keyboardHidden) {
        onKeyboardChange(newConfig.keyboardHidden);

        keyboardHidden = newConfig.hardKeyboardHidden;
    }

}

public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;

//todo
private void onKeyboardChange(int keyboardHidden) {

}

//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {

}
于 2016-06-03T15:38:08.550 回答
-1

我写了样本

此存储库可以帮助检测键盘状态,而无需假设“键盘应该超过屏幕的 X 部分”

于 2019-09-14T12:56:58.687 回答
-1

试试这个,对我来说工作得很好

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm.isActive())
        //Keyboard is active
于 2021-07-07T07:02:37.537 回答