這周完成了一個需求,涉及到EditText和軟鍵盤,其中一個要求是:鍵盤出現時,文本輸入框和鍵盤的間距大於16dp。android
如今回頭看,沒想到EditText能折騰出新鮮東西。bash
整個頁面的佈局走常規路線,我畫了一張草圖,其中ScrollView和EditText用紅色標註了一下:
app
這個問題,寫項目的時候我是沒有遇到的,爲了這篇文章寫Demo時出現了,真是amazing。ide
而後這個問題的解法,在搜索引擎上查找到,可是結果並不理想,看到的方案太複雜,好比:使用ViewTreeObserver.OnGlobalLayoutListener監聽整個頁面佈局變化,在回調裏滑動ScrollView佈局
因而我對比了一下項目和Demo關於使用EditText的代碼。發現區別在於:layout_height的值。ui
<EditText
...
android:paddingTop="18dp"
android:paddingBottom="18dp"
android:layout_height="wrap_content"/>複製代碼
因此,這個問題咱們能夠規避掉。至於這兩種寫法,爲什麼會形成鍵盤表現不一樣,有興趣的朋友能夠深拔拔看,又知道的也請告知一下,感謝~this
圖【EditText 被鍵盤遮蓋部分底部】:
搜索引擎
首先,ScrollView會自動滾動合適的距離將帶焦點的View滑動到屏幕的可見區域,這個知識在作此次的需求以前我已知道。後面全部的思路,就是如何利用ScrollView的這一特色。spa
解法一:3d
設置EditText的bottom padding,結合InsetDrawable,在視覺上能夠以假亂真。
最後沒有采起這種方案,這個方案會致使EditText和它底部臨近的控件間距變大(若是沒底部沒有其餘控件這個方案就很適合)。
效果大概是這樣的:
解法二:
巧用ScrollView自動滾動帶焦點View的特色。當帶焦點的View不在屏幕可見的範圍時,ScrollView內部會根據這個View的bounds,計算一個合適的偏移量,而後將該View滾動到可見的合適範圍。
咱們看一下ScrollView#onSizeChanged()
方法的源碼:
@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
View currentFocused = findFocus();
if (null == currentFocused || this == currentFocused)
return;
// If the currently-focused view was visible on the screen when the
// screen was at the old height, then scroll the screen to make that
// view visible with the new screen height.
if (isWithinDeltaOfScreen(currentFocused, 0, oldh)) {
//獲取View的位置寬高信息等
currentFocused.getDrawingRect(mTempRect);
offsetDescendantRectToMyCoords(currentFocused, mTempRect);
//根據此時獲取到焦點的View計算滑動距離,
int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
doScrollY(scrollDelta);
}
}複製代碼
computeScrollDeltaToGetChildRectOnScreen
方法名好長😅,打開這個方法的文檔,咱們能看到:
Compute the amount to scroll in the Y direction in order to get a rectangle completely on the screen (or, if taller than the screen, at least the first screen size chunk of it).
大意是:計算rectangle表示的View徹底可見須要的的滑動距離,這個是咱們須要的方法。該方法的修飾符是protected,意味着咱們經過能夠繼承的方式重寫該方法,經過修改該方法的返回值,達到咱們的目的,整個修改的開發量巨小,以下:
class FITBScrollView(
context: Context?,
attrs: AttributeSet?
) : ScrollView(context, attrs) {
var extraMargin = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
16f,
resources.displayMetrics
).roundToInt()
/**
* EditText獲取焦點後,ScrollView會將它滑動到屏幕顯示的範圍內,這個時候這個方法會被觸發,用來計算Y軸滾動距離
*/
override fun computeScrollDeltaToGetChildRectOnScreen(rect: Rect?): Int {
//Child非徹底可見時
if (rect?.bottom ?: 0 > scrollY + height - extraMargin) {
return super.computeScrollDeltaToGetChildRectOnScreen(rect) + extraMargin
}
return super.computeScrollDeltaToGetChildRectOnScreen(rect)
}
}複製代碼
效果大概是這樣的:
但願對有相似問題的開發朋友們有幫助。尤爲是EditText被軟鍵盤遮擋的問題,不但願你們用太複雜的方案,由於複雜的方案經常意味着更多的風險。