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

前端 未结 30 1392
情书的邮戳
情书的邮戳 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条回答
  • 2020-11-22 11:37

    You can use the callback result of showSoftInput() and hideSoftInput() to check for the status of the keyboard. Full details and example code at

    http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android

    0 讨论(0)
  • 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
    }
    
    0 讨论(0)
  • 2020-11-22 11:38

    I created a simple class that can be used for this: https://github.com/ravindu1024/android-keyboardlistener. Just copy it in to your project and use as follows:

    KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
    {
        @Override
        public void onToggleSoftKeyboard(boolean isVisible)
        {
            Log.d("keyboard", "keyboard visible: "+isVisible);
        }
    });
    
    0 讨论(0)
  • 2020-11-22 11:40

    A little bit more compacted Kotlin version based on the answer of @bohdan-oliynyk

    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()
    }
    
    0 讨论(0)
  • 2020-11-22 11:40

    If you support apis for AndroidR in your app then you can use the below method.

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

    Note: This is only available for the AndroidR and below android version needs to follow some of other answer or i will update it for that.

    0 讨论(0)
  • 2020-11-22 11:43

    Here is a workaround to know if softkeyboard is visible.

    1. Check for running services on the system using ActivityManager.getRunningServices(max_count_of_services);
    2. From the returned ActivityManager.RunningServiceInfo instances, check clientCount value for soft keyboard service.
    3. The aforementioned clientCount will be incremented every time, the soft keyboard is shown. For example, if clientCount was initially 1, it would be 2 when the keyboard is shown.
    4. On keyboard dismissal, clientCount is decremented. In this case, it resets to 1.

    Some of the popular keyboards have certain keywords in their classNames:

    1. Google AOSP = IME
    2. Swype = IME
    3. Swiftkey = KeyboardService
    4. Fleksy = keyboard
    5. Adaptxt = IME (KPTAdaptxtIME)
    6. Smart = Keyboard (SmartKeyboard)

    From ActivityManager.RunningServiceInfo, check for the above patterns in ClassNames. Also, ActivityManager.RunningServiceInfo's clientPackage=android, indicating that the keyboard is bound to system.

    The above mentioned information could be combined for a strict way to find out if soft keyboard is visible.

    0 讨论(0)
提交回复
热议问题