那些年我们踩过的坑-SwipeRefreshLayout
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出现的问题,也可以更好的理解它们之间的关系。
上面的分析也只是我个人的理解,如果有什么不对的地方,希望大家能指出,多多指教。