SwipeRefreshLayout想必大家已经很熟悉了。在很多主流的APP上面已经有看到一个会变颜色的刷新圈圈。这是SwipeRefreshLayout自带的一个行为。而通常我们使用刷新都会和listview或者RecyclerView一起使用。然而这里会有一个潜在的冲突:当RecyclerView还没有到顶部时,已经触发了SwipeRefreshLayout的刷新动作。
在XML里面的布局如下:
.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swp_manageOvRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
.support.v7.widget.RecyclerView
android:id="@+id/rv_fMvCompanyList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
.support.v4.widget.SwipeRefreshLayout>
然后在Java文件里头,我们获取到SwipeRefreshLayout的句柄,然后设置它的下拉的位置、变化的样式、刷新监听等等。
首先是位置设置,setProgressViewOffset()几个参数说明如下
1. 参数1:true,下拉的时候,不会从上面滑动下来,而是在固定的位置缩放出来,缩放回去。
2. 参数2:刷新圈圈出现的位置,单位为像素。
3. 参数3:刷新的圈圈最后定住的位置,单位也是像素。
swipeRefreshLayout.setProgressViewOffset(true, BuildConfig.swipeLayoutStartPointFromTop, BuildConfig.swipeLayoutEndPointFromTop);
然后是刷新滚动时变换的颜色的设置,最多可以设置4种不同的颜色。第一种颜色是默认呈现给用户看到的。在动画的时候,会依次切换不同颜色,直到刷新完成或者取消。
1. 参数1:动画的颜色。
2. 同上。
3. 同上。
4. 同上。
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary,
R.color.blueLight,
R.color.btn_cm_bg_pressed,
R.color.withe);
刷新监听,API提供了setOnRefreshListener()方法,只要实现OnRefreshListener接口就可以了。然后在onRefresh()方法里面实现需要的操作。当完成操作之后,调用swipeRefreshLayout.setRefreshing(false)方法取消刷新就可以了。
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//加载数据,刷新布局等操作
//....
swipeRefreshLayout.setRefreshing(false);
}
});
在上面我们看到我们swipeRefreshLayout结合RecyclerView一起使用了。在做项目的时候,大部分的机型是没有什么问题的,但是在一款华为的手机上,就发现了一个问题:滑动冲突了。在往下滑的时候,RecyclerView还没有到达顶部就触发了下拉刷新的动作。这里产生的具体原因未知,得去看源码才知道。
解决方法是,在swipeRefreshLayout类的内部,实现了OnChildScrollUpCallback()方法,这个方法返回值指示swipeRefreshLayout内部的view有没有可能向上滚动,返回true表示可以滚动,返回false表示不可滚动,触发刷新。如果里面的控件是自定义的,就需要重写这个方法。API提供了setOnChildScrollUpCallback()方法给我们重写。如下:
swipeRefreshLayout.setOnChildScrollUpCallback(new SwipeRefreshLayout.OnChildScrollUpCallback() {
@Override
public boolean canChildScrollUp(SwipeRefreshLayout parent, @Nullable View child) {
if (mRecyclerView == null) {
return false;
}
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
return linearLayoutManager.findFirstCompletelyVisibleItemPosition() != 0;
}
});
在这里我们先获得RecyclerView的布局管理器LinearLayoutManager这里使用的是线性布局,还有网格布局GridLayoutManager和瀑布流StaggeredGridLayoutManager布局管理器,可以很方便的实现绚丽的各种界面。
然后findFirstCompletelyVisibleItemPosition()返回的位置是可见区域第一个全部可见的item的位置,这里注意:是整个item全部出现了才算。如果返回的位置不等于0,结果为true,那么swipeRefreshLayout里面的RecyclerView标志为可滚动的,RecyclerView就可以往上滚动。当到了第一个全部item可见的时候,返回的position为0,结果false,那么说明RecyclerView已经到顶了,那么RecyclerView就标志位不可滚动的状态,继续下拉就会触发swipeRefreshLayout的刷新机制了。
以上就是关于swipeRefreshLayout需要注意的一个问题,我的重点是要讲swipeRefreshLayout和RecyclerView之间的冲突,因为我们使用RecyclerView绝大部分的需求都是要自定义item布局的,所以Google也明确的说了,当你是自定义item布局时,必须要重写OnChildScrollUpCallback()方法–原文说明:Override this if the child view is a custom view.
如有任何问题,请及时与我联系,谢谢!