美文网首页
一不小心踩到 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