拓展开源库SwipeToLoadLayout实现EmptyView和Empty时自动禁用LoadMore

  Android应用开发中,经常需要使用到界面的下拉刷新和上拉加载,在support v7之前,一般都是用ListView去做列表视图,而ListView对EmptyView是提供支持的,并且有许多开源库拓展了ListView使其支持了下拉刷新和上拉加载,但是许多这种拓展都会在ListView现实EmptyView时失效,原因就是ListView实际上已经被Gone了。

  在support v7之后,google提供了一个神器,RecyclerView,相信大部分人都已经不陌生了,RecyclerView提供了更强大的Recycler机制,能够完美实现ListView的基础上,使开发者的代码更简洁,效率更高,并且能实现各种不同的布局。但是凡事都有个但是,RecyclerView目前为止并没有提供Header,Footer,EmptyView的内部支持,所以大部分的开发者的方案是使用其他拓展RecyclerView或者Layout来实现,google提供的SwipeLayout可以实现下拉刷新的功能,但是如果要实现上拉加载或者更改header都是比较麻烦的。

  但是现在有许多的开源方案可以实现,比如SwipeToLoadLayout,虽然这个开源项目的star并不多,但是它是我发现的最方便实现下拉刷新和上拉加载的开源库了。建议大家也可以使用试试。

  美中不足的是,SwipeToLoadLayout并没有提供EmptyView的内部支持,相信大部分的这类开源库都没有支持吧。但是没关系,我们可以自己去实现它,并且附带实现自动开启关闭LoadMore的功能(在Empty时就应该自动关闭Loadmore)注:希望你在阅读下面的代码之前先已经研究并使用过SwipeToLoadLayout了

  1、首先我们需要添加一个EmptyView在swipe_target里面

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <com.duoniu.benfu.widget.layout.SwipeToLoadLayoutEmptySupport
 3     android:id="@+id/swipeToLoadLayout"
 4     xmlns:android="http://schemas.android.com/apk/res/android"
 5     xmlns:app="http://schemas.android.com/apk/res-auto"
 6     android:orientation="vertical" android:layout_width="match_parent"
 7     android:layout_height="wrap_content"
 8     app:swipe_style="classic">
 9 
10     <include
11         android:id="@+id/swipe_refresh_header"
12         layout="@layout/layout_logo_header"/>
13 
14 
15     <RelativeLayout
16         android:id="@id/swipe_target"
17         android:layout_width="match_parent"
18         android:layout_height="wrap_content">
19 
20         <com.duoniu.benfu.widget.recyclerview.RecyclerViewEmptySupport
21             android:id="@+id/recyclerView"
22             android:layout_width="match_parent"
23             android:layout_height="wrap_content">
24 
25         </com.duoniu.benfu.widget.recyclerview.RecyclerViewEmptySupport>
26 
27         <include layout="@layout/empty_or_error"
28             android:id="@+id/emptyView"
29             android:visibility="gone"/>
30     </RelativeLayout>
31 
32 
33 
34     <include
35         android:id="@+id/swipe_load_more_footer"
36         layout="@layout/layout_classic_footer"/>
37 
38 </com.duoniu.benfu.widget.layout.SwipeToLoadLayoutEmptySupport>

  可以看到,我们的swipe_target不在只是单独的一个RecyclerView了,而且一个RelativeLayout,里面放了一个RecyclerView和一个EmptyView.当然,这个EmptyView你可以任意实现,默认visibility是gone了。

  2、拓展RecyclerView

  为了使RecycleView能够支持EmptyView,我们需要监听到RecyclerView的item数量变换来控制EmptyView的现实

 1 public class RecyclerViewEmptySupport extends RecyclerView {
 2 
 3     private View emptyView;
 4 
 5     private WeakReference<SwipeToLoadLayout> weakSwipeToLoadLayout;
 6 
 7     private AdapterDataObserver emptyObserver = new AdapterDataObserver() {
 8         @Override
 9         public void onChanged() {
10             Adapter<?> adapter = getAdapter();
11             if (adapter != null && emptyView != null){
12                 if (adapter.getItemCount() == 0){
13                     emptyView.setVisibility(View.VISIBLE);
14                 }
15                 else{
16                     emptyView.setVisibility(View.GONE);
17                 }
18                 if (weakSwipeToLoadLayout != null && weakSwipeToLoadLayout.get() != null){
19                     weakSwipeToLoadLayout.get().setLoadMoreEnabled(adapter.getItemCount() > 0);
20                 }
21             }
22         }
23     };
24 
25     public RecyclerViewEmptySupport(Context context) {
26         super(context);
27     }
28 
29     public RecyclerViewEmptySupport(Context context, AttributeSet attrs) {
30         super(context, attrs);
31     }
32 
33     public RecyclerViewEmptySupport(Context context, AttributeSet attrs, int defStyle) {
34         super(context, attrs, defStyle);
35     }
36 
37 
38 
39     @Override
40     public void setAdapter(Adapter adapter) {
41         super.setAdapter(adapter);
42         if (adapter != null){
43             adapter.registerAdapterDataObserver(emptyObserver);
44         }
45         emptyObserver.onChanged();
46     }
47 
48     public void setEmptyView(View emptyView) {
49         this.emptyView = emptyView;
50     }
51 
52     public void setSwipeToLoadLayout(SwipeToLoadLayout swipeToLoadLayout) {
53         this.weakSwipeToLoadLayout = new WeakReference<>(swipeToLoadLayout);
54     }
55 
56 }

  我们使用了sdk中的AdapterDataObserver来监听数据变化,在onChange中实现如果item已经为0了就现实emptyView,反之不显示,另外,如果item已经为0了就禁用SwipeToLoadLayout的加载更多功能。

  3、拓展SwipeToLoadLayout

  细心的朋友会发现RecyclerViewEmptySupport的emptyView字段是从外部set的,很明显,RecyclerView是没法知道它边上有个兄弟View的,所以需要父布局去set

 1 public class SwipeToLoadLayoutEmptySupport extends SwipeToLoadLayout {
 2 
 3 
 4     public SwipeToLoadLayoutEmptySupport(Context context) {
 5         super(context);
 6     }
 7 
 8     public SwipeToLoadLayoutEmptySupport(Context context, AttributeSet attrs) {
 9         super(context, attrs);
10     }
11 
12     public SwipeToLoadLayoutEmptySupport(Context context, AttributeSet attrs, int defStyleAttr) {
13         super(context, attrs, defStyleAttr);
14     }
15 
16     @Override
17     protected void onFinishInflate() {
18         super.onFinishInflate();
19         View targetView = this.findViewById(R.id.swipe_target);
20         if (targetView != null) {
21             View emptyView = targetView.findViewById(R.id.emptyView);
22             View recyclerView = targetView.findViewById(R.id.recyclerView);
23             if (recyclerView instanceof RecyclerViewEmptySupport){
24                 RecyclerViewEmptySupport recyclerViewEmptySupport = ((RecyclerViewEmptySupport) recyclerView);
25                 recyclerViewEmptySupport.setSwipeToLoadLayout(this);
26                 if (emptyView != null && recyclerView != null) {
27                     recyclerViewEmptySupport.setEmptyView(emptyView);
28                 }
29             }
30 
31         }
32 
33     }
34 }

  4、使用SwipeToLoadLayoutEmptySupport

  其实到此为止,我们已经拓展完成了,接下来就是使用了,使用上并没有什么技巧,就只是在所有需要上拉加载,下拉刷新以及空视图的地方include一下我们刚开始写的布局即可(是不是感觉很方便?)

  

  

你可能感兴趣的:(拓展开源库SwipeToLoadLayout实现EmptyView和Empty时自动禁用LoadMore)