一不小心踩到 SwipeRefreshLayout 的坑里

一般情況下,我們都是把 SwipeRefreshLayout 當做需要有刷新功能的父布局使用,類似這樣:

  <android.support.v4.widget.SwipeRefreshLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.NestedScrollView
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <!--content-->
    </android.support.v4.widget.NestedScrollView>
  </android.support.v4.widget.SwipeRefreshLayout>

在這種情況下, SwipeRefreshLayout 會自動找到子布局,進行刷新判斷等操作,一切正常。但是,最近一直都在使用 ConstraintLayout,并且是否能觸發(fā)下拉刷新需要我設(shè)置 OnChildScrollUpCallback 自己進行判斷。于是乎布局變成了這樣:

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <android.support.v4.widget.SwipeRefreshLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="@+id/scroll_view"
    app:layout_constraintLeft_toLeftOf="@+id/scroll_view"
    app:layout_constraintRight_toRightOf="@+id/scroll_view"
    app:layout_constraintTop_toTopOf="@+id/scroll_view"/>

  <android.support.v4.widget.NestedScrollView
    android:id="@+id/scroll_view"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <!--content-->
  </android.support.v4.widget.NestedScrollView>
  
</android.support.constraint.ConstraintLayout>

SwipeRefreshLayout 里面沒有了子布局,這樣問題就出現(xiàn)了,會發(fā)現(xiàn)無論如何設(shè)置都不能觸發(fā)下拉刷新動作了。以前有子布局的時候是正常的,現(xiàn)在沒了,難道是這里出了問題?能想到的就是在 SwipeRefreshLayout 里面搜索 getChildAt 方法在什么地方有調(diào)用,調(diào)用來干嘛來。
首先找到的是在 ensureTarget() 中有調(diào)用,源碼如下:

    private void ensureTarget() {
        // Don't bother getting the parent height if the parent hasn't been laid
        // out yet.
        if (mTarget == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (!child.equals(mCircleView)) {
                    mTarget = child;
                    break;
                }
            }
        }
    }

這段代碼就是用來確定刷新的子布局,由于我們并沒有設(shè)置子布局,所以 mTarget 在運行完之后應(yīng)該還是 null。
下一段代碼是在 onMeasure 中:

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        mTarget.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
        mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY));
        mCircleViewIndex = -1;
        // Get the index of the circleview.
        for (int index = 0; index < getChildCount(); index++) {
            if (getChildAt(index) == mCircleView) {
                mCircleViewIndex = index;
                break;
            }
        }
    }

這段代碼使用 getChildAt 是為了確定 mCircleView 的位置,也就是刷新時候的那個圓環(huán)。乍看無關(guān),仔細一看,就發(fā)現(xiàn)了問題所在。在針對 SwipeRefreshLayout 本身做完測量之后,先是確定了 mTarget,要是 mTarget 為 null 的話,就直接返回了。要是不為空,才會對 mCircleView 進行測量操作。也就是說在沒有子布局的情況下,mCircleView 是沒有進行測量的操作的,所以 mCircleView 的 getMeasuredHeight() 和 getMeasuredWidth() 都將返回0,這就導(dǎo)致了刷新小圓圈顯示不出來。
所以在使用 SwipeRefreshLayout 的時候一定要記得給它添加一個子布局。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容