关键字:SmartRefreshLayout使用 下拉刷新 上拉加载 BaseRecyclerviewAdapterHelper
前言
下拉刷新和上拉加载是每个APP中最基本的功能,这里将这个功能进行整理。可以作为一个模板代码去使用,这样避免了每次开发都要去思考,直接复制粘贴使用即可。
实现的功能点:
1.使用MVP实现下拉刷新及加载更多;
2.采用懒加载,禁止viewPager预加载,区分出两种刷新:初始化刷新、下拉刷新;
3.采用BaseRecyclerviewAdapterHelper的上拉加载达到更好的上拉加载效果;
4.上拉加载:无数据、加载错误、数据全部加载完成三种视图的区分显示;
5.下拉刷新无数据空视图的展示;
目录
- 技术方案选型
- 具体代码
- 分页字段的理解
利用SmartRefreshLayout实现下拉刷新
利用 baserecyclerviewadapterhelper 实现加载更多
1.Presenter 层,DemoPresenter.java 如下,只列出简要P层获取新闻列表,M层的实现这里就不列出了,这个不是本文重点。
public class DemoPresenter {
DemoRepository mRepository;
// 获取新闻列表
public void getNews(int pageNumber, int loadType){
mRepository.loadNewsListByTopic(pageNumber, new DemoDataSource.LoadNewsCallback() {
@Override
public void onNewsLoaded(List<News> newsList) {
mView.loadSuccess(newsList, loadType);
}
});
}
}
布局设置
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical">
<!— 这里屏蔽掉加载更多功能 -->
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width=“match_parent"
app:srlEnableLoadMore="false"
android:layout_height="match_parent">
<!-- 添加经典下拉头部刷新 -->
<com.scwang.smartrefresh.layout.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srlAccentColor="@android:color/white" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
</ai.botbrain.smartrefresh.layout.SmartRefreshLayout>
</LinearLayout>
代码中设置
public class TestFragment extends BaseFragment implements TestView {
// 标识分页的字段
private int mPageNum = 0;
private static final int COUNT = 10;
private int mRefreshType;//mRefreshType变量名用小写,防止看混淆
// 首次刷新
public static final int FIRST_LOAD = 1;
// 刷新
public static final int REFRESH = 2;
// 上拉加载
public static final int LOAD_MORE = 3;
private View mNoDataView;
@BindView(R.id.refreshLayout)
SmartRefreshLayout mRefreshLayout;
@BindView(R.id.recyclerView)
PowerfulRecyclerView mRecyclerView;
private MyAdapter mAdapter;
private MyPresenter mPresenter;
@Override
public void initData() {
super.initData();
mAdapter = new MyAdapter();
// 自定义加载中,加载失败,加载完成的布局
mAdapter.setLoadMoreView(new CustomLoadMoreView());
}
@Override
public void initView(View rootView) {
super.initView(rootView);
mNoDataView = getLayoutInflater().inflate(R.layout.empty_view, (ViewGroup) mRecyclerView.getParent(), false);
}
@Override
public void initListener() {
super.initListener();
// 下拉刷新回调
mRefreshLayout.setOnRefreshListener(refreshLayout -> {
mPageNum = 0;
mPresenter.loadDataList(mPageNum, FIRST_LOAD);
});
// 上拉加载回调
mAdapter.setOnLoadMoreListener(() -> {
mPresenter.loadDataList(mPageNum, LOAD_MORE);
}, mRecyclerView);
mRecyclerView.setAdapter(mAdapter);
// 刚进来的时候来个初始化刷新
mRefreshLayout.autoRefresh();
}
@Override
public void onLoadNewsSuccess(List<Circle> data, int loadType) {
// 防范空指针发生
if (ListUtils.isEmpty(data))
data = new ArrayList<>();
mPageNum++;
// int size = data == null ? 0 : data.size();
int size = data.size();
// mRefreshLayout.finishLoadmore();
mRefreshLayout.finishRefresh(0);
// 注意:不要忘记添加 break 否则~
switch (loadType) {
case FIRST_LOAD:
mAdapter.initRefresh(data);// 如果data为null这里就会引发空指针
break;
case REFRESH:
mAdapter.initRefresh(data);
break;
case LOAD_MORE:
mAdapter.loadMoreData(data);
break;
}
if (mAdapter.getData().size() == 0) { //空视图情况
mAdapter.setEmptyView(noDataView);
} else if (size == 0) { //上拉加载出来的数据为0,认为加载结束
mAdapter.loadMoreEnd(false);
} else {//完成了本次加载,还有更多数据(注意逻辑是在else中,这里写错可能导致不停的上拉加载数据)
mAdapter.loadMoreComplete();
}
}
// 加载失败的情况,显示重试页面
@Override
public void onLoadNewsError() {
// 弹出提示
mTipView.show();
// 如果一开始进入没有数据,显示重试布局
if (ListUtils.isEmpty(mAdapter.getData)) {
showRetry();
} else { // 显示(加载失败,请点我重试)
mAdapter.loadMoreFail();
}
// 收起刷新
mRefreshLayout.finishLoadmore();
mRefreshLayout.finishRefresh(0);
// 发送加载完成的事件
...
}
}
Adapter 中
public class MyAdapter extends BaseMultiItemQuickAdapter<Data, BaseViewHolder> {
public MyAdapter() {
// 这里传入null具体看源码
super(null);
addItemType(Data.TYPE_STYLE_1, R.layout.item_circle_layout);
}
// 初始化刷新
public void initRefresh(List<Circle> circle) {
this.mData.clear();
this.mData.addAll(circle);
notifyDataSetChanged();
}
// 初始化刷新
public void initRefresh(List<Circle> circle) {
this.mData.addAll(circle);
notifyDataSetChanged();
}
// 普通10条
public void refreshDataNotClear(List<Article> data) {
mData.addAll(0, data);
notifyDataSetChanged();
}
// 加载更多
public void loadMoreData(List<Circle> circle) {
this.mData.addAll(circle);
notifyDataSetChanged();
}
@Override
protected void convert(BaseViewHolder helper, Circle item) {
int viewType = helper.getItemViewType();
switch (viewType) {
case Article.TYPE_LK_LANDSCAPE:
renderBanner(helper, item);
break;
case :
break;
}
}
实体类
public class New implements MultiItemEntity {
public static final int TYPE_ONE_PIC = 100;
private int itemType;
public void setItemType(int itemType) {
this.itemType = itemType;
}
@Override
public int getItemType() {
return itemType;
}
}