How do I detect if software keyboard is visible on Android Device or not?

前端 未结 30 1882
情书的邮戳
情书的邮戳 2020-11-22 10:59

Is there a way in Android to detect if the software (a.k.a. \"soft\") keyboard is visible on screen?

30条回答
  •  旧时难觅i
    2020-11-22 11:37

    It works with adjustNothing flag of activity and lifecycle events are used. Also with 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)
        }
    }
    

    Useful method to keep view always above the keyboard

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

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

    Where getFullScreenSize

    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
    }
    

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

提交回复
热议问题