CoordinatorLayout,AppBarLayout中Edittext被键盘覆盖问题解决

 <androidx.coordinatorlayout.widget.CoordinatorLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                 <com.google.android.material.appbar.AppBarLayout
                    android:id="@+id/appbarLayout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <com.google.android.material.appbar.CollapsingToolbarLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        app:layout_scrollFlags="scroll|exitUntilCollapsed">

                        <androidx.appcompat.widget.LinearLayoutCompat
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="vertical"
                            android:visibility="visible">

                             <Edittext/>
            </androidx.appcompat.widget.LinearLayoutCompat>

        </com.google.android.material.appbar.AppBarLayout>
      </com.google.android.material.appbar.CollapsingToolbarLayout>
 </androidx.constraintlayout.widget.ConstraintLayout>

以上就是Edittext所处的位置。
我上外网翻了了一遍,发现google其实是不建议CollapsingToolbarLayout中使用Edittext,因为它对 adjustResize 是无效的,并且短时间内不会解决。

所以只能自己手动解决。

步骤思路:

1.获取Edittext在屏幕中的位置
2.获取键盘弹出高度
3.计算需要滑动的高度
4.监听触碰edittext被触碰,然后滑动AppBarLayout

首先,获取edittext 在屏幕中的位置:

val location = IntArray(2)
edittext.getLocationOnScreen(location)
//location[1] 即位置

接着获取键盘高度:

private var softKeyboardHeight = 0
private var keyboardOpen = false
private val mGlobalLayoutListener = OnGlobalLayoutListener {
        val r = Rect()
        //获取当前窗口实际的可见区域
        window.decorView.getWindowVisibleDisplayFrame(r)
        val height: Int = r.height()
        if (mWindowHeight == 0) {
            //一般情况下,这是原始的窗口高度
            mWindowHeight = height
        } else {
            if (mWindowHeight != height) {
                //两次窗口高度相减,就是软键盘高度
                softKeyboardHeight = mWindowHeight - height
                keyboardOpen = true
            }
        }
    }
 //onCreate的时候注册监听
window.decorView.viewTreeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener)
//记得销毁
 override fun onDestroy() {
        super.onDestroy()
        window.decorView.viewTreeObserver.removeOnGlobalLayoutListener(mGlobalLayoutListener)
    }

计算上滑动高度:

val limit = ScreenUtil.getDisplayHeight() - softKeyboardHeight.toFloat() //键盘弹窗位置
val current = location[1] + ScreenUtil.dip2px(40f) - ScreenUtil.getStatusBarHeight(this) //输入框底部位置,40f 是输入框高度,getStatusBarHeight 状态栏高度

val distance = current - limit; //要滑动高度
                     

监听,滑动:

 val touchListener = object : View.OnTouchListener {
        override fun onTouch(v: View?, event: MotionEvent?): Boolean {
            scrollAppBar()
            return false
        }
    }
edittext.setOnTouchListener(touchListener)

fun scrollAppBar(){
  if (keyboardOpen) {
      val layoutParams: ViewGroup.LayoutParams = appbarLayout.getLayoutParams()
      val behavior = (layoutParams as CoordinatorLayout.LayoutParams).behavior
      if (behavior is AppBarLayout.Behavior) {
           if (distance > 0) {
               behavior.topAndBottomOffset = (appBarScrollHeight - distance).toInt()
           }
       }
    keyboardOpen = false
 }
}

搞定。

代码是从项目中抽象出来的,实际业务逻辑复杂的多,核心代码已经在上面了,大家举一反三吧。

补充下:
appBarScrollHeight 是,AppBarLayout 当前的滚动位置。这个是需要实时记录的,以下是代码。

var appBarScrollHeight = 0
appbarLayout.addOnOffsetChangedListener(object : AppBarLayout.OnOffsetChangedListener {
            override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) {
                appBarScrollHeight = verticalOffset
            }

        })
上一篇:Android——可折叠式的标题栏


下一篇:CoordinatorLayout滑动抖动问题