我们目前的项目是采用单 Activity 多 Fragment 的架构模式, AndroidManifest.xml 内 MainActivity 的配置如下所示。

<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
状态隐藏,如果我们设置了这个属性,键盘状态就一定是隐藏的,不管上个界面是什么状态,也不管当前界面有没有输入的需求,就是不显示软键盘。adjustResize
调整大小状态,这个属性表示 Activity 的主窗口总是会被调整大小来保证软键盘的显示空间。如果界面中有可滑动控件,显示效果跟 adjustUnspecified 显示效果一样;如果界面中没有可滑动控件,软键盘可能会盖住一些控件(布局的位置不会发生变化,可能获取了焦点的控件被软键盘盖住)。
一般来说,我们的布局分为两种

  1. 底部按钮被滚动布局包裹
  2. 底部按钮不被滚动布局包裹

第一种布局是不会出现软键盘把底部按钮顶起的情况,首先软键盘的打开实际上是一个 Dialog,而我们在配置文件内的 adjustResize 属性是在页面的根布局 decorView 的子 view 也就是一个线性布局内通过设置 paddingBottom = 软键盘高度,这样其实相当于把整个滚动布局的高度减少了,所以底部的按钮也只是变为需要滚动才能看到。
第二种情况通常为一个继续按钮始终处于页面的底部,中间的内容可以滚动,当根布局的内边距等于软键盘高度时,底部按钮就看起来像是被顶起。




android 键盘显示 安卓键盘界面_安卓


从大的方向来说可以通过修改 windowSoftInputMode 来设置布局对软键盘的处理方式,当然也可以通过监听软键盘,这种修改的细粒度更小。

1、监听软键盘的打开收起

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、修改 windowSoftInputModeadjustPan
如果设置了这个属性,当软键盘弹出的时候,系统会通过布局的移动,来保证用户要进行输入的输入框在用户的视线范围内。如果界面没有可滑动控件,显示效果和 adjustUnspecified 效果一样;如果界面有可滑动控件,在软键盘显示的时候,可能会有一些内容显示不出来。

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