EditText與軟鍵盤的相愛相殺

這周完成了一個需求,涉及到EditText和軟鍵盤,其中一個要求是:鍵盤出現時,文本輸入框和鍵盤的間距大於16dp。android

如今回頭看,沒想到EditText能折騰出新鮮東西。bash

整個頁面的佈局走常規路線,我畫了一張草圖,其中ScrollView和EditText用紅色標註了一下:
app



1、鍵盤出現時,遮蓋住了部分EditText

這個問題,寫項目的時候我是沒有遇到的,爲了這篇文章寫Demo時出現了,真是amazing。ide

而後這個問題的解法,在搜索引擎上查找到,可是結果並不理想,看到的方案太複雜,好比:使用ViewTreeObserver.OnGlobalLayoutListener監聽整個頁面佈局變化,在回調裏滑動ScrollView佈局

因而我對比了一下項目和Demo關於使用EditText的代碼。發現區別在於:layout_height的值。ui

  • layout_height="xxdp"時,會出現軟鍵盤遮蓋部分EditText的問題
  • 下面這種寫法則不會致使軟鍵盤遮蓋的問題

    <EditText      
        ...
        android:paddingTop="18dp"      
        android:paddingBottom="18dp"      
        android:layout_height="wrap_content"/>複製代碼

因此,這個問題咱們能夠規避掉。至於這兩種寫法,爲什麼會形成鍵盤表現不一樣,有興趣的朋友能夠深拔拔看,又知道的也請告知一下,感謝~this

圖【EditText 被鍵盤遮蓋部分底部】:
搜索引擎



2、如何控制文本輸入框和鍵盤的間距

首先,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被軟鍵盤遮擋的問題,不但願你們用太複雜的方案,由於複雜的方案經常意味着更多的風險。

相關文章
相關標籤/搜索