轻松实现RecycleView的下拉刷新、加载更多
来源:互联网 发布:中国网络教育大学 编辑:程序博客网 时间:2024/06/06 07:08
那如同这个题目,这里面涉及的东西其实还是比较多的,RecycleView SwipeRefreshLayout,下拉刷新(这个就是SwipeRefreshLayout的),加载更多。
SwipeRefreshLayout
这个是Google自己封装的一个下拉刷新的控件,里面使用了5.0开始的嵌套滑动机制,有兴趣的朋友可以去看看源码!使用起来其实就涉及到以下方法:
setOnRefreshListener()
下拉刷新的相关回调。
setRefresh()
通知是否开始刷新或者刷新完成。(坑1)
setColorSchemeColors()
loading的时候progressbar
的颜色,支持多个。
SwipeRefreshLayout的坑
进入页面调用setRefresh(true)
,更不不显示刷新的小圆圈?!
简单的说,这个就是在oncreate()方法执行的时候,view还没有绘制出来,这个时候你设置刷新不刷新其实都一样的,解决方法,post一下!
mRecyclerView.post(new Runnable() { @Override public void run() { mRefreshLayout.setRefreshing(refresh); } });
RecycleView
RecycleView
其实出现都有一定的年头了,前几天公司来面试的居然说他还没有用过。。这个也是醉醉的!
RecycleView
是ListView
的强力升级!加入了holder便于管理和复用相同的类型。
就我目前掌握的情况,RecycleView对于ListView有了以下的不同:
1、加入了LayoutManager
用用管理各种类型的布局,而且通过不同的布局可以实现横向、竖向、瀑布式的等各种复杂的布局。
2、加入Holder
来管理相关布局和复用,对于每一种Type的View你都要创建一个对应的Holder
来管理它!
3、取消了header和bottom布局。
4、没有现成的itemClick
回调。
5、引入了丰富的动画效果。(坑4)
6、添加了丰富的数据刷新的方法,可以局部刷新了!(坑3)
7、可自定义相关分割线。
8、支持swipe删除和drag排序。(ItemTouchHelper
帮助类)
9、默认是不显示scrollBar
的(坑2)
10、可以设置不同类型holder占据不同的空间(ItemColumnSpan)
上面这些不是所有的都讲,其实本文主要涉及的就是相关adapter
,里面对应不同的holder
,及相关的封装。然后说说踩了哪些坑。
基本思路
- 1、明确什么时候开始加载更多?
下拉刷新就调用SwipeRefreshLayout
相关就好了,那么加载更多呢?这个就要自己去写相关的布局了。然后第一个问题,什么时候加载更多??因为RecycleView
有各种布局,所以判断最后一个也是要区分不同的adapter的!
- 2、加载更多有多少种情况?
大致有三种,正在加载更多;加载更多错误;没有更多数据了;
具体实现
1、监听滑动,满足条件开始加载更多。
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (null != scrollListener) { scrollListener.onScrolled(SwipeRefreshRecycleView.this, dx, dy); } if (null == manager) { throw new RuntimeException("you should call setLayoutManager() first!!"); } if (null == adapter) { throw new RuntimeException("you should call setAdapter() first!!"); } if (manager instanceof LinearLayoutManager) { int lastCompletelyVisibleItemPosition = ((LinearLayoutManager) manager).findLastCompletelyVisibleItemPosition(); if (adapter.getItemCount() > 1 && lastCompletelyVisibleItemPosition >= adapter.getItemCount() - 1 && adapter.isHasMore()) { adapter.isLoadingMore(); if (null != listener) { listener.onLoadMore(); } } int position = ((LinearLayoutManager) manager).findFirstVisibleItemPosition(); if (lastTitlePos == position) { return; } lastTitlePos = position; } if (manager instanceof StaggeredGridLayoutManager) { int[] itemPositions = new int[2]; ((StaggeredGridLayoutManager) manager).findLastVisibleItemPositions(itemPositions); int lastVisibleItemPosition = (itemPositions[1] != 0) ? ++itemPositions[1] : ++itemPositions[0]; if (lastVisibleItemPosition >= adapter.getItemCount() && adapter.isHasMore()) { adapter.isLoadingMore(); if (null != listener) { listener.onLoadMore(); } } } }
2、定义自己的加载更多的ViewHolder。
3.定义相关的方法实时更新ViewHolder的三种状态。
public class NewBottomViewHolder extends RecyclerView.ViewHolder{ @Bind(R.id.footer_container) public LinearLayout contaier; @Bind(R.id.progressbar) ProgressBar pb; @Bind(R.id.content) TextView content; @Nullable private final SwipeRefreshRecycleView.OnRefreshLoadMoreListener mListener; public NewBottomViewHolder(View itemView, SwipeRefreshRecycleView.OnRefreshLoadMoreListener listener) { super(itemView); ButterKnife.bind(this,itemView); mListener = listener; } public void bindDateView(int state) { switch (state) { case AdapterLoader.STATE_LASTED: contaier.setVisibility(View.VISIBLE); contaier.setOnClickListener(null); pb.setVisibility(View.GONE); content.setText("--- 没有更多了 ---"); break; case AdapterLoader.STATE_LOADING: contaier.setVisibility(View.VISIBLE); content.setText("加载更多!!"); contaier.setOnClickListener(null); pb.setVisibility(View.VISIBLE); break; case AdapterLoader.STATE_ERROR: contaier.setVisibility(View.VISIBLE); pb.setVisibility(View.GONE); content.setText("--- 加载更多失败点击重试 ---"); contaier.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onLoadMore(); } content.setText("加载更多!!"); pb.setVisibility(View.VISIBLE); } }); break; } }}
4.定义相关扩展方法便于用户自己定义底部布局及相关状态处理。
这里就必须详细讲讲Adapter里面的相关方法了!
getItemCount(),在RecycleView知道它一共有多少数量的Item需要展示,返回0之后不会执行剩余的方法!
onCreateViewHolder(ViewGroup parent, int viewType),某种Type的Holder第一次创建的时候会调用该方法,当然没有复用的时候也会去创建,一旦复用了,改方法不会再执行了!
onBindViewHolder(RecyclerView.ViewHolder holder, int position),每一次更新对应itemView的时候都会调用该方法,所以在该方法中要实时的刷新数据!(因为存在复用,所以刷新的时候一定要彻底!!!)
以上三个方法是必须实现的,因为在父类adapter里是抽象滴!
还有一个方法也比较重要:
getItemViewType(int position),这个方法是返回对应pos的类型的,如果你只有一个类型,不需要重写该方法,默认返回的是0。
是不是这么说起来比ListView还要爽一点儿?不用去判断什么convertView==null
!
@Overridepublic final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_BOTTOM: if (loadMore != null) { RecyclerView.ViewHolder holder = onBottomViewHolderCreate(loadMore); if (holder == null) { throw new RuntimeException("You must impl onBottomViewHolderCreate() and return your own holder "); } return holder; } else { return new BottomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_footer, parent, false)); } default: return onViewHolderCreate(parent, viewType); }}@Overridepublic final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (getItemViewType(position) == TYPE_BOTTOM) { loadState = loadState == STATE_ERROR ? STATE_ERROR : isHasMore() ? STATE_LOADING : STATE_LASTED; if (loadMore != null) { try { onBottomViewHolderBind(holder, loadState); } catch (Exception e) { e.printStackTrace(); } } else { try { ((BottomViewHolder) holder).bindDateView(loadState); } catch (Exception e) { e.printStackTrace(); } } } else { onViewHolderBind(holder, position); }}
这里在RefreshRecycleAdapter<T>
中实现了刚刚说的三个方法,并且相关的已经加final修饰了!所以之后你只需要实现如下方法来完成你自己的item填充就好了:
RecyclerView.ViewHolder onViewHolderCreate(ViewGroup parent, int viewType);void onViewHolderBind(RecyclerView.ViewHolder holder, int position);
对于加载更多的几种状态的更改,提供如下的相关方法!
boolean isHasMore();void isLoadingMore();void loadMoreError();
对于创建自己制定的加载更多的布局,提供如下方法扩展!
void setLoadMoreView(View view);RecyclerView.ViewHolder onBottomViewHolderCreate(View loadMore);void onBottomViewHolderBind(RecyclerView.ViewHolder holder, int loadState);
还没有说的那就是数据源相关的方法。提供了set和append两种方式!
void setList(List<T> data);void appendList(List<T> data);@Overridepublic final void appendList(List<T> data) { int positionStart = list.size(); list.addAll(data); int itemCount = list.size() - positionStart; if (positionStart == 0) { notifyDataSetChanged(); } else { notifyItemRangeInserted(positionStart + 1, itemCount); }}
还是那话,这些方法都是RefreshRecycleAdapter<T>
里面写好的,我们写自己的adapter时更本不用去care!只需要去调用setList()
或者appendList()
就好了!!
说到这里不得不提提RecycleView
刷新数据的相关方法和坑!
在notifyDataSetChanged()
的基础上, RecycleView
增加了一系列的方法用于增删改。。
notifyItemInserted();notifyItemRangeInserted();notifyItemChanged();notifyItemRangeChanged();notifyItemRemoved();notifyItemRangeRemoved();
在使用的过程中,发现调用notifyItemChanged()
之后不会去执行onBindViewHolder()
,(坑3 坑4)这个就导致刷新没有触发了!最后搜到的结果是因为mRecyclerView.setItemAnimator(new DefaultItemAnimator())引起的,解决方案是复写相关方法
@Overridepublic boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads) { return true;}
小结
首先通过addList()或者appendList()的方法设置相关数据源。
滑动过程中需要加载更多时回调相关方法,并在adapter中通知相关状态刷新。
adapter.isLoadingMore(); if (null != listener) { listener.onLoadMore(); }
加载错误的时候调用相关的方法通知状态改变。
adapter.loadMoreError();
创建BottomHolder
的时候判断有没有设置自定义的view,如果有,那么就去走子类的onBottomViewHolderCreate()
方法创建自定义的Bottomholder
,然后实时更新相关数据!
@Overridepublic final void setLoadMoreView(@NonNull View view) { loadMore = view;}if (loadMore != null) { RecyclerView.ViewHolder holder = onBottomViewHolderCreate(loadMore); if (holder == null) { throw new RuntimeException("You must impl onBottomViewHolderCreate() and return your own holder "); } return holder; }
最后在onBottomViewHolderBind(RecyclerView.ViewHolder holder, int state)
的方法中执行bindDateView(state)
实时刷新相关的状态。
public void bindDateView(int state) { switch (state) { case AdapterLoader.STATE_LASTED: contaier.setVisibility(View.VISIBLE); contaier.setOnClickListener(null); pb.setVisibility(View.GONE); content.setText("--- 没有更多了 ---"); break; case AdapterLoader.STATE_LOADING: contaier.setVisibility(View.VISIBLE); content.setText("加载更多!!"); contaier.setOnClickListener(null); pb.setVisibility(View.VISIBLE); break; case AdapterLoader.STATE_ERROR: contaier.setVisibility(View.VISIBLE); pb.setVisibility(View.GONE); content.setText("--- 加载更多失败点击重试 ---"); contaier.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onLoadMore(); } content.setText("加载更多!!"); pb.setVisibility(View.VISIBLE); } }); break; }}
PS 最后还有默认是不显示scrollBar
的问题,这个问题,似乎必须在xml里面配置,不能代码直接new RecycleView
。然后可以使用相关代码控制ScrollBar
是否显示!
mRecyclerView.setVerticalScrollBarEnabled(true)<android.support.v7.widget.RecyclerView android:id="@+id/recycle_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent" />
另外对于特性8、10这里就不详细介绍了,滑动删除和拖拽排序在TouchHelperCallback
中有相关支持!方法如下:
@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { if (callBack != null) { callBack.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); } return true;}@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { if (callBack != null) { callBack.onItemDismiss(viewHolder.getAdapterPosition()); }}
详细的可以参照相关Demo-FangShiActivity
gradle快速集成
compile 'com.lovejjfg.powerrecycle:powerrecycle:1.0.0'
相关下载
演示Demo下载
项目中的使用
—- Edit By Joe —-
- 轻松实现RecycleView的下拉刷新、加载更多
- SwipeRefreshLayout +RecycleView实现上拉加载更多和下拉刷新
- 自己封装的工具类,使用原生SwipeRefreshLayout+RecycleView实现下拉刷新和加载更多
- RecycleView控件的使用(三) 实现上拉加载更多下拉刷新功能
- Android之RecyclerView轻松实现下拉刷新和加载更多
- RecycleView下拉刷新控件的封装(包括下拉刷新和加载更多 )
- 下拉刷新,加载更多的实现
- PullToReFresh 实现 RecycleView 横向滑动的刷新和加载更多
- RecycleView从显示到下拉刷新和加载更多
- Android之RecycleView下拉刷新上滑加载更多
- RecycleView添加下拉刷新、上拉加载更多
- MaterialRefreshLayout实现下拉刷新,下拉加载更多
- RecycleView的上啦加载下拉刷新
- RecyclerView 轻松实现下拉刷新,上拉加载更多,添加HeaderView
- Android ListView下拉刷新上拉加载更多的实现
- Android实现下拉刷新,滑动加载更多的功能
- listview下拉刷新,上拉加载更多的实现方法
- 下拉刷新、上拉加载更多功能的实现
- C中如何调用C++函数?
- LintCode(easy)合并排序数组
- 【动归经典】最长公共子串
- 【题解】2015.10.17题目
- 【转载】FloodFill算法的优化
- 轻松实现RecycleView的下拉刷新、加载更多
- 【转载】SPFA最短路算法解析
- Linux内部的时钟处理机制全面剖析
- 【打CF,学算法——二星级】Codeforces 705B Spider Man (简单博弈)
- 【转载】IPEOI1 1-4题解题报告
- 2015.11.29总结+部分题解(未完待续)
- 【转载】NOIP2015 TG D2T3 transport
- 一步成高手:终极图解内存(上篇)
- 【转载】NOIP2015 TG D1T2 message