RecyclerView实现的列表,默认情况是不带下拉刷新和上拉加载更多功能的,但是在我们的实际项目当中,我们不可能一下子把所有数据返回,为了提高用户体验,需要提供下拉刷新与加载更多的功能.
一、SwipeRefreshLayout
1、介绍
SwipeRefreshLayout 是谷歌v4包里19.1版本开始的提供的下拉刷新控件,但它是android5.0新特性中material design设计风格。Swiperefreshlayout刷新动画老版本v4包会是顶部左右流动的线条动画,高版本的v4包是常见的圆圈转的动画效果.
2、SwipeRefreshLayout常用方法
(1)setOnRefreshListener(OnRefreshListener)
添加下拉刷新监听,顶部下拉时会调用这个方法,在里面实现请求数据的逻辑,设置下拉进度条消失等等
(2)setRefreshing(boolean)
显示或者隐藏刷新动画
(3)isRefreshing()
检查是否处于刷新状态
(4)setColorSchemeResources()
设置进度条的颜色主题,参数为可变参数,并且是资源id,可以设置多种不同的颜色,每转一圈就显示一种颜色,以前的setColorScheme()方法已经弃用了
二、SwipeRefreshLayout+RecyclerView实现下拉刷新功能
1、布局文件
(1)MainActivity布局文件
使用SwipeRefreshLayout包裹RecyclerView就可以了
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swip"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
(2)RecyclerView的item布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="#ff33b5e5"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center"
tools:text="别看了,我就是一个TextView" />
</RelativeLayout>
2、MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwip;
private MainAdapter mAdapter;
private List<String> mDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
mAdapter = new MainAdapter(this,mDatas);
mRecyclerView.setAdapter(mAdapter);
mSwip = (SwipeRefreshLayout) findViewById(R.id.swip);
mSwip.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
mSwip.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//实际开发中,我们在这里发送网络请求获取数据
mDatas.add(0,"嘿嘿!我是下拉刷新的数据!");
mAdapter.notifyDataSetChanged();
mSwip.setRefreshing(false);
}
});
}
private void initData() {
mDatas = new ArrayList<>();
for (int i = 'A'; i < 'Z'; i++) {
mDatas.add("" + (char) i);
}
}
}
3、效果图及小结
很简单,而且效果也不错,可惜的是SwipeRefreshLayout 本身只支持下拉刷新(ˇˍˇ)
三、实现上拉加载更多功能
1、怎样实现
RecyclerView有个滑动监听的方法,我们可以通过这个方法来实现上拉加载更多功能
RecycleView .addOnScrollListener(RecycleView .OnScrollListener);
这里参数需要一个RecycleView .OnScrollListener ,OnScrollListener 是一个抽象类,为了充分保证 RecyclerView 的灵活性,Android 本身是没有对这个滑动接口做处理,需要我们根据需求来实现它
2、抽象类RecycleView .OnScrollListener
public abstract static class OnScrollListener {
/**
* 滑动状态改变时的回调
* @param recyclerView
* @param newState:SCROLL_STATE_IDLE 滑动停止
* SCROLL_STATE_DRAGGING 正在触摸或者滑动
* SCROLL_STATE_SETTLING 不是在外界控制下的自动滑动↓
* 调用scrollToPosition()方法时会触发这个状态
*/
public void onScrollStateChanged(RecyclerView recyclerView, int newState){}
/**
* 在RecyclerView 发生滑动时调用
* @param dx 滑动时水平方向的偏移量,有正负之分
* @param dy 滑动时竖直方向的偏移量,有正负之分
*/
public void onScrolled(RecyclerView recyclerView, int dx, int dy){}
}
1)如果我们想要在用户停止滑动之后触发加载更多,可以在onScrollStateChanged方法中来判断状态是否是SCROLL_STATE_IDLE,然后再判断是否滑到底部
2)如果我们想要在用户滑动过程中触发加载更多,只需要在onScrolled方法中判断是否滑到底部
3、实现我们自己的RecycleView .OnScrollListener
(1)先来了解几个参数
public class LoadMoreScrollListener extends RecyclerView.OnScrollListener{
private LinearLayoutManager mLinearLayoutManager;
private int totalItemCount; //item总数量
private int visibleItemCount; //可见item总数量,只显示了部分也算可见
private int firstVisibleItemPosition; //屏幕上第一个可见item位置位置,只显示部分也算
private int lastVisibleItemPosition; //屏幕上最后一个可见item位置位置,只显示部分也算
private int firstCompletelyVisibleItemPosition;//屏幕上第一个完全显示出的item位置
private int lastCompletelyVisibleItemPosition; //屏幕上最后一个完全显示出的item位置
//PS : 最后2个position返回值有个问题:当你的item的高度比手机屏幕还高,会返回-1
public LoadMoreScrollListener (LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = mLinearLayoutManager.getItemCount();
visibleItemCount = mLinearLayoutManager.getChildCount();
firstVisibleItemPosition
= mLinearLayoutManager.findFirstVisibleItemPosition();
lastVisibleItemPosition
= mLinearLayoutManager.findLastVisibleItemPosition();
firstCompletelyVisibleItemPosition
= mLinearLayoutManager.findFirstCompletelyVisibleItemPosition();
lastCompletelyVisibleItemPosition
= mLinearLayoutManager.findLastCompletelyVisibleItemPosition();
Log.e("totalItemCount", "" + totalItemCount );
Log.e("visibleItemCount", "" + visibleItemCount);
Log.e("部分可见", "firstVisibleItemPosition" + firstVisibleItemPosition);
Log.e("部分可见", "lastVisibleItemPosition" + lastVisibleItemPosition);
Log.e("完全可见", "firstCompletelyVisibleItemPosition" + firstCompletelyVisibleItemPosition);
Log.e("完全可见", "lastCompletelyVisibleItemPosition" + lastCompletelyVisibleItemPosition);
Log.e("-", "------------------------------------");
}
在Activity中加入我们的监听方法
mRecyclerView.addOnScrollListener(new LoadMoreScrollListener(layoutManager));
通过下面Log及效果图就能完全了解这几个参数的意义了
(2)实现加载更多逻辑
了解以上几个参数之后,我们需要判断下列情况:
1、是否是向上滑动
2、是否滑动到底部
3、当前是否正在加载数据
OK,我们可以来实现我们的逻辑了
public abstract class LoadMoreScrollListener extends RecyclerView.OnScrollListener {
private LinearLayoutManager mLinearLayoutManager;
private int totalItemCount;
private int visibleItemCount;
private int lastVisibleItemPosition;
private boolean isLoading = false;//控制不要重复加载更多
private int previousTotal;
public LoadMoreScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = mLinearLayoutManager.getItemCount();
visibleItemCount = mLinearLayoutManager.getChildCount();
lastVisibleItemPosition
= mLinearLayoutManager.findLastVisibleItemPosition();
if (isLoading) {
if (totalItemCount > previousTotal) {//说明数据已经加载结束
isLoading = false;
previousTotal = totalItemCount;
}
}
if (visibleItemCount > 0 && !isLoading
&& lastVisibleItemPosition >= totalItemCount - 1//最后一个item可见
&& totalItemCount > visibleItemCount) {//数据不足一屏幕不触发加载更多
onLoadMore();
isLoading = true;
}
}
public abstract void onLoadMore();
}
Activity中我们通过SwipeRefreshLayout刷新动画来看一看加载更多的效果
private int loadMoreNum;
mRecyclerView.addOnScrollListener(new LoadMoreScrollListener(layoutManager) {
@Override
public void onLoadMore() {
mSwip.setRefreshing(true);
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
mDatas.add("哼哼哼!我是上拉加载更多出来的数据"+loadMoreNum);
mAdapter.notifyDataSetChanged();
mSwip.setRefreshing(false);
loadMoreNum++;
}
},1000);
}
});