美文网首页
一不小心踩到 SwipeRefreshLayout 的坑里

一不小心踩到 SwipeRefreshLayout 的坑里

作者: chrnie | 来源:发表于2017-09-16 11:00 被阅读323次

一般情况下,我们都是把 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,并且是否能触发下拉刷新需要我设置 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 里面没有了子布局,这样问题就出现了,会发现无论如何设置都不能触发下拉刷新动作了。以前有子布局的时候是正常的,现在没了,难道是这里出了问题?能想到的就是在 SwipeRefreshLayout 里面搜索 getChildAt 方法在什么地方有调用,调用来干嘛来。
首先找到的是在 ensureTarget() 中有调用,源码如下:

    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;
                }
            }
        }
    }

这段代码就是用来确定刷新的子布局,由于我们并没有设置子布局,所以 mTarget 在运行完之后应该还是 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 的位置,也就是刷新时候的那个圆环。乍看无关,仔细一看,就发现了问题所在。在针对 SwipeRefreshLayout 本身做完测量之后,先是确定了 mTarget,要是 mTarget 为 null 的话,就直接返回了。要是不为空,才会对 mCircleView 进行测量操作。也就是说在没有子布局的情况下,mCircleView 是没有进行测量的操作的,所以 mCircleView 的 getMeasuredHeight() 和 getMeasuredWidth() 都将返回0,这就导致了刷新小圆圈显示不出来。
所以在使用 SwipeRefreshLayout 的时候一定要记得给它添加一个子布局。

相关文章

网友评论

      本文标题:一不小心踩到 SwipeRefreshLayout 的坑里

      本文链接:https://www.haomeiwen.com/subject/tnjysxtx.html