效果圖 隨著輸入的文本自動增加高度,鍵盤上方自定義菜單佈局,隨鍵盤彈起 點擊編輯框,自動滾動到焦點處輸入 佈局層次 <ConstraintLayout> <ScrollView> <LinearLayout> <Edittext/> <自定義佈局/> </LinearLayout> </Scroll ...
效果圖
隨著輸入的文本自動增加高度,鍵盤上方自定義菜單佈局,隨鍵盤彈起
點擊編輯框,自動滾動到焦點處輸入
佈局層次
<ConstraintLayout>
<ScrollView>
<LinearLayout>
<Edittext/>
<自定義佈局/>
</LinearLayout>
</ScrollView>
<鍵盤上方自定義佈局/>
</ConstraintLayout>
想要實現自動焦點定位,需要手動計算滾動距離,系統也有自帶的滾動效果,不過因為這裡有自定義佈局,所以不相容
系統原生自帶了鍵盤彈起頂起佈局的方式,並且點擊 edittext 後 scrollView 里的 edittext 會自動滾動定位到焦點區域
有它的便捷也有它的問題,比如自定義鍵盤上方的佈局後,定位不准確,因為自定義的佈局不屬於鍵盤,系統不會計算在內,而且自動定位部分手機不起效果,需要做相容
滾動後內容區域不在鍵盤上方自定義佈局上,而是滾動到鍵盤上方,缺少了自定義佈局的那段高度
滾動方法很簡單,直接調用 scrollView.smoothScrollTo(0, scrollTo) 方法就行
然後需要提前測量好鍵盤上方佈局的高度跟鍵盤彈起的高度
鍵盤直接使用 Blankj 工具類 KeyboardUtils 監聽,佈局高度直接測量就行
接下來監聽鍵盤彈起狀態 onSoftInputChanged,每次彈起鍵盤手動給 scrollView 設置 bottomMargin,為了讓佈局在鍵盤彈起時在鍵盤上方位置,如果有自定義佈局需要把佈局高度也計算上
到這裡鍵盤彈起結束,接下來進入核心,自動滾動定位焦點
首先是獲取到當前焦點的精確坐標,有了坐標才能跳轉
一開始我嘗試了 touch 觸摸事件,通過點擊的位置來獲取坐標,計算滑動距離,不過這個方案很快被推翻
因為不是很準確,加上內容是自適應高度,滑動距離過長時問題多
後來發現可以通過 getLineForOffset 方法獲取編輯框當前的行數,然後在通過 getLineBounds 方法獲取行坐標
獲取坐標後需要計算出 scrollView 滑動的距離
滑動距離 = 當前坐標 - 鍵盤彈起高度 + 自定義佈局高度
如果沒有自定義佈局就不用算
private fun scrollEdit() { //當前游標的坐標-鍵盤高度 val scrollTo = getCurrentEditY() - boardHeight + menuHeight mBinding.scrollView.post { //計算實際滾動的位置 mBinding.scrollView.smoothScrollTo(0, scrollTo) } }
得到滾動距離後直接在 onTextChanged 監聽里去調用上面的方法就行了,此時只要文本更改就會重新定位,自動滾動到你輸入的內容區域上
註意點
1、焦點自動定位問題
如果存在 ScrollView 嵌套 Edittext,那麼會有部分手機系統會自動滾動到焦點位置的情況,但是這不符合我們的自定義需求,畢竟系統定位的不准確,沒有導航欄適配,
滾動的位置會出現遮擋鍵盤上方佈局的情況,所以需要重寫方法去限制一下
2、導航欄適配問題
因為底部有自定義佈局,會跟隨鍵盤彈起,所以需要適配系統導航欄,否則底部自定義佈局不好適配
3、自動滾動問題
核心就在於滾動定位,需要自己計算滾動距離,並且在輸入的時候自動定位到該區域
並且如果調用滾動方法時,需要在變動之後調用,否則會跟系統測量結果有衝突,也就是在點擊後調用 post 方法,在裡面做滾動操作