使用微信的朋友圈會發現,點選某一條評論後輸入框會彈出來,然後所點選的那一項會自動地滾動到輸入框上方的位置,這樣如果開始所點選的評論在螢幕很下方的話,就不會被輸入框遮住,雖然微信這一點在我的MX2頻繁點幾次後滾動的位置就完全錯誤了,但據說在有些機型上效果還不錯,還有其他地方可能會有類似的需求,比如登入時軟鍵盤可能會把登入按鈕遮住。
要實現這個功能需要注意的地方主要有兩點:
- 什麼時候進行滾動操作,以及有可能還需要在輸入框消失時回滾回去。
- 輸入框彈出後所點選的項要滾動到輸入框上方,這就需要我們計算要滾動的距離。
針對第一點,評論框出現在軟鍵盤的上方,一般情況下軟鍵盤出來後評論框的位置會移動,也就是會出現Layout操作,所以可以在Layout時計算滾動距離,時機就是:
view.getViewTreeObserver().addOnGlobalLayoutListener
評論框Layout時的回撥,在這裡計算需要滾動的距離。
接下來就是滾動距離的計算。
滾動距離=所點選的項底部的Y座標 - 軟鍵盤彈出後輸入框頂部的Y座標
所以只要知道這兩個座標就可以知道需要滾動的距離,獲得座標以很簡單,通過getGlobalVisibleRect就可以了,當然還有其他方法,但由於是計算的差值,保證兩次計算座標時用同一個就可以了。獲得座標後直接smoothScrollBy。
原理就是這麼簡單,不過要實現起來,細節問題搞得人噁心。
比如說輸入框初始的可見性可能是GONE,也可能是Visible,如果是GONE,那麼軟鍵盤彈出時可能會有兩個過程,1.從GONE到Visible會layout一次,2.軟鍵盤彈出又layout一次,隱藏時一樣。介面剛顯示時也會layout,所以這就需要判斷在onGlobalLayout時是否需要過濾事件。
在MX2上實驗,smoothScrollBy有兩個引數,第二個是duration,如果duration過小,可能你傳入的distance是600,系統卻可能只會滾動500。
有時可能也需要在輸入框的onFocusChange中滾動。
如果到了列表底部,計算出的距離可能和實際滾動的距離也不一樣,這種情況也可以用setSelectionFromTop的方法讓所點選的Item在螢幕最上方,當然也可以再計算偏移,總之異常繁瑣。
如果是像登入這種情況,UI簡單的,要加個ScrollView,也比較好處理,軟鍵盤彈出時直接滾動到底部,隱藏時滾動到頂部。
總之,要實現自動滾動,首先就要有一個控制元件隨著軟鍵盤的彈出消失而移動位置,軟鍵盤彈出後出現在軟鍵盤的上方,哪怕它看不見只是作為一個anchor。
其次,需要計算滾動距離,看情況有所不同,也是最麻煩的,可能需要知道輸入框的狀態是隱藏,顯示在螢幕底部而軟鍵盤沒出來,還是軟鍵盤出來了。不過在輸入框初始隱藏在佈局最下方的情況下,這三種情況輸入框的座標也只有3個值,也可以根據這個值判斷輸入框的狀態,當然不排除有些輸入法可以調整軟鍵盤高度而使用者又很配合地在輸入時調整。
反正如果有這需求就噁心死吧。在專案三個地方實現,大致方法都是一樣的,細節都有差異。