完美解決EditText和ScrollView的滾動衝突(下)

上篇文章完美解決EditText和ScrollView的滾動衝突(上)中提到咱們自己寫了一個判斷EditText是否可以在垂直方向上滾動的方法,那麼這個方法是如何得來的呢?
其實Android API裏是有一個判斷控件是否可以在垂直方向上滾動的方法的,方法名字叫做canScrollVertically(int direction),代碼如下:

/**
     * Check if this view can be scrolled vertically in a certain direction.
     *
     * @param direction Negative to check scrolling up, positive to check scrolling down.
     * @return true if this view can be scrolled in the specified direction, false otherwise.
     */
    public boolean canScrollVertically(int direction) {
        final int offset = computeVerticalScrollOffset();
        final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
        if (range == 0) return false;
        if (direction < 0) {
            return offset > 0;
        } else {
            return offset < range - 1;
        }
    }

根據註釋不難得知此方法是用來判斷當前控件是否可以在垂直的方向上進行滾動的:當參數direction傳的是負值的時候,會判斷當前控件是否可以向上滾動;否則當參數direction傳的是非負值的時候,會判斷當前控件是否可以向下滾動。
由此得知我們完全可以利用此方法這樣來判斷一個控件是否可以在垂直方向上進行滾動:

if(editText.canScrollVertically(-1) || editText.canScrollVertically(0)) {
            //垂直方向上可以滾動
        }

那麼爲什麼不使用此方法呢?很無奈,因爲這個方法是在API 14(也就是Android4.0)才提供的方法,而很多時候我們需要兼容4.0以下的手機,所以並不能直接使用。雖然不能直接使用此方法,不過我們可以看一下它內部是怎麼實現的,直接抄過來不就得了!不過還有個悲劇的消息,computeVerticalScrollOffset()、computeVerticalScrollRange()和computeVerticalScrollExtent()這三個方法都是protected方法,所以我們仍然不能使用,沒辦法,我們只好一塊兒將這三個方法內部的實現都看一下。

1.computeVerticalScrollOffset()方法

首先是computeVerticalScrollOffset()方法:`

protected int computeVerticalScrollOffset() {
        return mScrollY;
    }

此方法定義在View中,並且EditText和TextView都沒有重寫,所以其返回的必然是mScrollY。那麼不適用這個方法我們該如何得到mScrollY呢?稍微猜測一下,既然有mScrollY這麼一個變量,那麼就應該有其的get方法。查看API,不難發現View中確實有個getScrollY()方法:

public final int getScrollY() {
        return mScrollY;
    }

2. computeVerticalScrollRange()方法

OK,第一個方法的值我們通過getScrollY()拿到了,接下來咱們來看第二個方法computeVerticalScrollRange():

protected int computeVerticalScrollRange() {
        return getHeight();
    }

在View中很快找到了此方法,但此方法使我們需要的嗎?不要忘了我們使用的是EditText!所以我們需要查看一下在EditText和TextView中是否對此方法進行了重載。不出我們所料,這個方法還真在TextView中進行了重載:

@Override
    protected int computeVerticalScrollRange() {
        if (mLayout != null)
            return mLayout.getHeight();

        return super.computeVerticalScrollRange();
    }

這個方法返回的是mLayout的高度,那麼我們怎麼獲得mLayout呢?剛剛咱們獲得mScrollY時使用了getScrollY()方法,那麼是不是會有一個getLayout()方法呢?抱着試試看的態度,忽然間發現在TextView中還真有這麼一個方法:

public final Layout getLayout() {
        return mLayout;
    }

3.computeVerticalScrollExtent()方法

恩,第二個方法的值我們也通過getLayout().getHeight()方法拿到了,現在咱們就來看一下最後一個方法computeVerticalScrollExtent():

protected int computeVerticalScrollExtent() {
        return getHeight();
    }

在View中我們同樣找到了此方法,但根據第二個方法的經驗,我們還應該去EditText和TextView中看一下有沒有重載。又一次地不出我們所料,這個方法果然在TextView中進行了重載:

@Override
    protected int computeVerticalScrollExtent() {
        return getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
    }

然後不難發現,此處使用的三個方法getHeight()、getCompoundPaddingTop()和getCompoundPaddingBottom()都是public方法,我們直接調用即可。
至此,我們已經可以完全對canScrollVertically(int direction)這個方法進行重寫了,而重寫之後的方法就是咱們上一篇博客中使用的canVerticalScroll(EditText editText)方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章