Android 踩坑记Android知识Android技术知识

那些年我们踩过的坑-SwipeRefreshLayout

2016-10-27  本文已影响1708人  Liuuuuuuzi

SwipeRefreshLayout 作为google提供的刷新库,相当简单实用,然而却也存在着问题,本文将简单讲述一下 SwipeRefreshLayout 的使用,和 使用过程中出现的问题及其解决方案,重点 谈谈 SwipeRefreshLayout 出现问题的原因。

简单使用

<com.nanke.cook.view.AutoSwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <com.kevin.wraprecyclerview.WrapRecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recycleView"
        android:padding="4dp"
        />

</com.nanke.cook.view.AutoSwipeRefreshLayout>t>

出现的问题:在刚进入到界面的时候需要显示刷新进度条,通过直接设置setRefreshing(true); 没有效果, 并没有显示

原因分析:

日志

由日志可以看出,在onMeasure 绘制之前,就调用了 setRefreshing,而在activity获取焦点过后,即onResume执行完毕后,View才会相应地调用onMeasure测量自身的大小,再来看 setRefreshing(boolean refreshing) 的源码:

    public void setRefreshing(boolean refreshing) {
        if (refreshing && mRefreshing != refreshing) {
            // scale and show
            mRefreshing = refreshing;
            int endTarget = 0;
            if (!mUsingCustomStart) {
                endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
            } else {
                endTarget = (int) mSpinnerFinalOffset;
            }
          //设置 显示刷新进度条的位置
            setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
                    true /* requires update */);
            mNotify = false;
            startScaleUpAnimation(mRefreshListener);
        } else {
            setRefreshing(refreshing, false /* notify */);
        }
    }

由上面可以看出,主要通过 setTargetOffsetTopAndBottom 来确定所要显示的位置,接着来看一下 setTargetOffsetTopAndBottom 的实现:

private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
        mCircleView.bringToFront();
        mCircleView.offsetTopAndBottom(offset);
        mCurrentTargetOffsetTop = mCircleView.getTop();
        if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
            invalidate();
        }
    }

可以看到,只是对 mCircleView 的属性进行设置,并没有主动调用 invalidate 去绘制,只有当 sdk<11时,做了调用。
所以也就很好理解,我们在还没有绘制之前,就设置显示刷新进度条,显示的位置都还没有确定,当然就不会显示了。

下面分析一下,网上出现的几种解决方案

方案一

refresh.setProgressViewOffset(false, 0, CommonUtil.dip2px(context, 24));
refresh.setRefreshing(true);

通过 setProgressViewOffset 初始化一个偏移量,同样分析一下源码:

public void setProgressViewOffset(boolean scale, int start, int end) {
        mScale = scale;
        mCircleView.setVisibility(View.GONE);
        mOriginalOffsetTop = mCurrentTargetOffsetTop = start;
        mSpinnerFinalOffset = end;
        mUsingCustomStart = true;
        mCircleView.invalidate();
    }

在 setProgressViewOffset 中 ,最终 执行了mCircleView.invalidate(),去主动绘制。

方案二

mSwipeRefreshLayout.post(new Runnable() {
               
        @Override
        public void run() {
            mSwipeRefreshLayout.setRefreshing(true);
        }
    });

通过post(Runnable runnable)方法放到UI线程排队执行。

总结

总结一下解决方法,就是在 SwipeRefreshLayout.onMeasure()之后,调用SwipeRefreshLayout.setRefreshing(true) 就好了。 总的来说,从这个问题可以看出,在Activity的生命周期以及 View的生命周期 ,它们是相互影响的,通过SwipeRefreshLayout出现的问题,也可以更好的理解它们之间的关系。

上面的分析也只是我个人的理解,如果有什么不对的地方,希望大家能指出,多多指教。

上一篇下一篇

猜你喜欢

热点阅读