我需要做一件非常简单的事情-找出软件键盘是否显示。这在Android中可行吗?
当前回答
一个不需要LayoutListener的方法
在我的情况下,我想在替换我的片段之前保存键盘的状态。我调用方法hideSoftInputFromWindow from onSaveInstanceState,它会关闭键盘并返回键盘是否可见。
这个方法很简单,但可能会改变键盘的状态。
其他回答
哇,安卓极客们有好消息了。是时候向旧的方式说再见了。 首先我将添加官方发布说明来阅读和了解更多关于这些方法/类,然后我们将看到这些神奇的方法/类
注意:在这些类/方法发布之前,不要将它们添加到你的发布应用中
如何检查键盘可见性
val insets = ViewCompat.getRootWindowInsets(view)
val isKeyboardVisible = insets.isVisible(Type.ime())
其他用途很少
如何获取键盘的高度
val insets = ViewCompat.getRootWindowInsets(view)
val keyboardHeight = insets.getInsets(Type.ime()).bottom
如何显示/隐藏键盘
val controller = view.windowInsetsController
// Show the keyboard
controller.show(Type.ime())
// Hide the keyboard
controller.hide(Type.ime())
注意:WindowInsetsController是在API-30中添加的,所以要等到向后兼容类不可用。
如何听键盘隐藏/显示事件
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
val isKeyboardVisible = insets.isVisible(Type.ime())
if (isKeyboardVisible) {
// Do it when keyboard is being shown
} else {
// Do it when keyboard is hidden
}
// Return the insets to keep going down this event to the view hierarchy
insets
}
一些改进,以避免在高密度设备上错误地检测软键盘的可见性:
Threshold of height difference should be defined as 128 dp, not 128 pixels. Refer to Google design doc about Metrics and Grid, 48 dp is comfortable size for touch object and 32 dp is minimum for buttons. Generic soft keyboard should include 4 rows of key buttons, so minimum keyboard height should be: 32 dp * 4 = 128 dp, that means threshold size should transfer to pixels by multiply device density. For xxxhdpi devices (density 4), the soft keyboard height threshold should be 128 * 4 = 512 pixels. Height difference between root view and its visible area: root view height - status bar height - visible frame height = root view bottom - visible frame bottom, since status bar height equal to the top of root view visible frame. 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; }
而不是假设差异编码,我做了这样的事情,因为我在我的应用程序中有菜单选项。
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
}
}
});
有一个隐藏的方法可以帮助这个,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()
}
}
参考@TacB0sS的回答,我在Kotlin中开发了一个类。希望这对你有所帮助。如果需要改进,请告诉我。
class KeyboardVisibilityObserver(val layRootContainer: View?, val keyboardVisibilityListener: KeyboardVisibilityListener?) {
var isKeyboardOpen = false
private set
private var keyBoardObserver = object : ViewTreeObserver.OnGlobalLayoutListener {
private val DefaultKeyboardDP = 100
// Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
private val EstimatedKeyboardDP = DefaultKeyboardDP + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 48 else 0
private val r = Rect()
override fun onGlobalLayout() {
if (layRootContainer != null) {
// Convert the dp to pixels.
val estimatedKeyboardHeight = TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP.toFloat(), layRootContainer.resources.displayMetrics).toInt()
// Conclude whether the keyboard is shown or not.
layRootContainer.getWindowVisibleDisplayFrame(r)
val heightDiff = layRootContainer.rootView.height - (r.bottom - r.top)
val isShown = heightDiff >= estimatedKeyboardHeight
if (isShown == isKeyboardOpen) {
// Log.d("Keyboard state", "Ignoring global layout change...");
return
}
isKeyboardOpen = isShown
keyboardVisibilityListener?.onKeyboardVisibilityChanged(isKeyboardOpen)
}
}
}
init {
layRootContainer?.viewTreeObserver?.addOnGlobalLayoutListener(keyBoardObserver)
}
// call this in onDestroy
fun removeObserver(){
layRootContainer?.viewTreeObserver?.removeOnGlobalLayoutListener(keyBoardObserver)
}
interface KeyboardVisibilityListener {
fun onKeyboardVisibilityChanged(isKeyboardOpen: Boolean)
}
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件