The bottom button of Android is jacked up by the soft keyboard. The problem is solved

Posted by jamz310 on Tue, 07 Dec 2021 21:49:24 +0100

Our current project adopts the architecture mode of single Activity and multiple fragments. The configuration of MainActivity in AndroidManifest.xml is as follows.

<activity
            android:name=".MainActivity"
            android:exported="true"
            android:windowSoftInputMode="stateHidden|adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
 </activity>

stateHidden State hiding. If we set this attribute, the keyboard state must be hidden. No matter what the state of the previous interface is or whether the current interface has input requirements, the soft keyboard is not displayed. adjustResize Resizing status. This property indicates that the main window of the Activity will always be resized to ensure the display space of the soft keyboard. If there are slidable controls in the interface, the display effect is the same as that of adjustUnspecified; If there are no slidable controls in the interface, the soft keyboard may cover some controls (the position of the layout will not change, and the controls that have obtained the focus may be covered by the soft keyboard). Generally speaking, our layout is divided into two types

  1. The bottom button is wrapped by the scroll layout
  2. The bottom button is not wrapped by the scrolling layout

In the first layout, the bottom button will not be pushed up by the soft keyboard. First, the opening of the soft keyboard is actually a Dialog, and our adjustResize attribute in the configuration file is in the sub view of the decorView of the root layout of the page, that is, in a linear layout, by setting paddingBottom = the height of the soft keyboard, In fact, this is equivalent to reducing the height of the whole scrolling layout, so the buttons at the bottom only need to scroll to see. In the second case, a continue button is always at the bottom of the page, and the content in the middle can be scrolled. When the inner margin of the root layout is equal to the height of the soft keyboard, the bottom button looks like being pushed up.

In the general direction, you can modify the windowSoftInputMode to set the processing method of the layout for the soft keyboard. Of course, you can also monitor the soft keyboard. This modification has less fine granularity.

1. Monitor the opening and closing of the soft keyboard

const val SOFT_KEY_BOARD_MIN_HEIGHT = 100

fun Fragment.registerFragment(bottomView: View){
    view?.registerView(bottomView)
}

fun Activity.registerActivity(bottomView: View){
    window?.decorView?.findViewById<View>(android.R.id.content)?.registerView(bottomView)
}

fun View.registerView(bottomView: View){
    var keyboardVisible = false
    viewTreeObserver.addOnGlobalLayoutListener {
        val r = Rect()
        getWindowVisibleDisplayFrame(r)
        val heightDiff: Int = rootView.height - r.bottom
        if(heightDiff > SOFT_KEY_BOARD_MIN_HEIGHT){
            if(!keyboardVisible){
                keyboardVisible = true
                bottomView.isClickable = false
                bottomView.visibility = View.INVISIBLE
            }
        }else{
            if(keyboardVisible){
                keyboardVisible = false
                bottomView.isClickable = false
                bottomView.visibility = View.VISIBLE
            }
        }
    }
}

2. Modify windowSoftInputMode adjustPan If this attribute is set, when the soft keyboard pops up, the system will move the layout to ensure that the input box to be input by the user is within the user's line of sight. If there are no slidable controls in the interface, the display effect is the same as adjustUnspecified; If the interface has slidable controls, some contents may not be displayed when the soft keyboard is displayed.

abstract class BaseFragment: Fragment() {

    private var keyboardType: Int = 0

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return LayoutInflater.from(context).inflate(getContentViewRes(), container, false)
    }

    override fun onResume() {
        super.onResume()
        arguments?.let {
            keyboardType = it.getInt("keyboardType",  0)
            if(keyboardType == 2){
                getBottomView()?.run {
                    registerFragment(this)
                }
            }else {
                onKeyboardSetting(keyboardType)
            }
        }
        initData()
        initView()
    }

    abstract fun getBottomView(): View?

    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
          if(!hidden){
                onKeyboardSetting(keyboardType)
            }else{
                onKeyboardSetting(0)
            }
    }

    override fun onDestroy() {
        super.onDestroy()
         onKeyboardSetting(0)
    }

    abstract fun initData()

    abstract fun initView()

    abstract fun getContentViewRes(): Int

}

fun Fragment.onKeyboardSetting(keyboardType: Int){
    if (keyboardType == 0){
        activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN or WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
    }else{
        activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
    }
}

Reference materials android:windowSoftInputMode property of Activity in Android