我需要做一件非常简单的事情-找出软件键盘是否显示。这在Android中可行吗?
当前回答
这可能不适合生产环境,因为它会打开键盘。注意,类似函数返回的布尔值在API中没有指定,因此是不可靠的。参考这里的文档…
https://developer.android.com/reference/android/view/inputmethod/InputMethodManager showSoftInput (% 20 int, android.view.View % 20 android.os.resultreceiver)
public boolean showSoftInput (View view,
int flags,
ResultReceiver resultReceiver)
注意,这个方法接受一个ResultReceiver。它可以得到结果:result_unchanged_shows, RESULT_UNCHANGED_HIDDEN, result_shows,或RESULT_HIDDEN。如果得到result_unchanged_show,则键盘是可见的。如果你需要它保持关闭如果它已经关闭了,你需要关闭它。
其他回答
就计算机而言,这是永远的问题,但这个问题仍然令人难以置信地相关!
所以我把上面的答案结合起来,做了一些改进……
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);
}
});
}
对我有用:)
注意: 如果你注意到DefaultKeyboardDP不适合你的设备播放的值,并发表评论,让每个人都知道应该是什么值…最终我们将得到适合所有设备的正确值!
要了解更多细节,请查看Cyborg上的实现
这些解决方案都不适用于棒棒糖。在Lollipop activityRootView.getRootView(). getheight()包含按钮栏的高度,而测量视图则不包含。我已经采用了上面最好/最简单的解决方案来处理棒棒糖。
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
}
}
});
有一种直接的方法可以找出答案。而且,它不需要任何布局更改。 所以,它也可以在沉浸式全屏模式下工作。 诀窍在于,您尝试隐藏或显示软键盘,并捕获尝试的结果。 没有恐慌,这并不真正显示或隐藏键盘。我们只要求状态。 为了保持最新,您可以简单地重复操作,例如,每200毫秒,使用处理器。 您可以在这里找到一个实现:https://stackoverflow.com/a/27567074/2525452
有一个隐藏的方法可以帮助这个,inputmethodmanager。getinputmethodwindowvisibleheight。但我不知道为什么要藏起来。
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()
}
}
在使用上述大多数建议添加固定数字的解决方案时,我刚刚遇到了一个错误。
S4的dpi很高,导致导航栏的高度为100px,因此我的应用程序认为键盘一直是打开的。
所以,随着所有新的高分辨率手机的发布,我认为使用硬编码值从长远来看不是一个好主意。
在各种屏幕和设备上进行测试后,我发现一个更好的方法是使用百分比。 获取decorView和你的应用内容之间的差异,然后检查这个差异的百分比。 从我得到的统计数据来看,大多数导航栏(无论大小、分辨率等)将占据屏幕的3%到5%。如果键盘是打开的,它会占据屏幕的47%到55%。
作为结论,我的解决方案是检查是否差异超过10%,然后我假设它的键盘打开。
推荐文章
- 如何在新的材质主题中改变背面箭头的颜色?
- androidviewpager与底部点
- 相同的导航抽屉在不同的活动
- 如何从视图中获得托管活动?
- 单一的TextView与多种颜色的文本
- 如何在非活动类(LocationManager)中使用getSystemService ?
- 在清单中注册应用程序类?
- Android:从数组中编程创建旋转器
- Android命令行工具sdkmanager总是显示:警告:无法创建设置
- 如何设置RecyclerView应用程序:layoutManager=""从XML?
- 在没有开发服务器的情况下在设备上构建和安装unsigned apk ?
- 操作栏和新引入的工具栏有什么不同?
- 调整浮动动作按钮图标大小(fab)
- Android Studio无法找到有效的Jvm(与MAC OS相关)
- android:在触摸移动时移动视图