作为ListView
和GridView
的替代者, RecyclerView
以它的灵活性著称,而且有着更好更完善的缓存处理机制。但是在使用RecyclerVew
的过程中有个很明显的问题:RecyclerView
没有为开发者提供addHeadView
和addFooterView
两个接口,这就为RecyclerView
的下拉刷新和上拉加载实现增加了难度,本文就为大家介绍RecyclerView
的下拉刷新和上拉加载的实现方式。
1. 下拉刷新
其实RecyclerView
的下拉刷新使用SwipeRefreshLayout
组件实现还是非常简单的。
SwipeRefreshLayout
也是Android SDK中为我们提供的一个布局容器类,它作为容器可以为它的子元素提供下拉刷新接口,而且使用方式也非常简单,我就直接上代码了
这就是RecyclerView
结合SwipeRefreshLayout
实现下拉刷新的布局方式,非常简单吧,写完布局文件之后,当然还要处理刷新的逻辑
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//在此处实现刷新获取数据,然后更新RecyclerView的数据源即可
}
});
写完这两段代码之后,RecyclerView
的下拉刷新就实现完成了,是不是很简单。不过还有个小小的问题需要注意下,那就是在刷新获取数据处理逻辑结束之后需要调用
mSwipeRefreshLayout.setRefreshing(false);
这个接口就是告诉SwipRefreshLayout
刷新动作已经结束,刷新进度条可以不用再显示了,否则的话视图顶部的刷新进度条会一直存在,当然如果你手动调用
mSwipeRefreshLayout.setRefreshing(true);
这个接口的话,刷新进度条就会显示出来。
2. 上拉加载
由于RecyclerView
中没有提供addFooterView
接口,所以我们没有办法像ListView中那样直接添加一个FooterView作为上拉加载的视图。但是RecyclerView.Adapter中也提供了public int getItemViewType(int position)
接口,我们可以为RecyclerView.Adapter
指定两种ViewType
,一个作为普通的ItemViewType
用来显示普通数据视图,一个作为FooterViewType
用来显示上拉加载视图,这样的话我们就需要在展示数据的基础上为RecyclerView.Adapter
额外增加一条数据用来显示添加的FooterView,这个特定Adapter的实现逻辑如下:
1. 定义两个ViewType分表用来区分普通是数据视图和上拉加载视图
private static final int VIEW_TYPE_FOOTER = 0;
private static final int VIEW_TYPE_ITEM = 1;
2.重写getItemCount()
方法,在原有数据的基础上增加一条数据用来显示FooterView
@Override
public int getItemCount() {
return mList.size() + 1;//在原有数据的基础增加一个数据用来显示FooterView
}
3.重写getItemViewType(int position)
方法,用来判断当前加载显示何种视图
@Override
public int getItemViewType(int position) {
if(position + 1 == getItemCount()) {//最后一条数据显示FooterView
return VIEW_TYPE_FOOTER;
}
return VIEW_TYPE_ITEM;
}
4.在onCreateViewHolder
方法中根据viewType初始化对应的视图
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_FOOTER) {
return onCreateFooterViewHolder(parent, viewType);
} else if(viewType == VIEW_TYPE_ITEM) {
return onCreateItemViewHolder(parent, viewType);
}
return null;
}
5.在onBindViewHolder
方法中根据viewType绑定显示对应的视图数据
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case VIEW_TYPE_ITEM:
onBindItemViewHolder(holder, position);
break;
case VIEW_TYPE_FOOTER:
onBindFooterViewHolder(holder, position, mLoadStatus);
break;
default:
break;
}
}
整个Adapter完整的代码如下:
public class DemoAdapter extends RecyclerView.Adapter {
private LoadStatus mLoadStatus = LoadStatus.CLICK_LOAD_MORE;//上拉加载的状态
private static final int VIEW_TYPE_FOOTER = 0;
private static final int VIEW_TYPE_ITEM = 1;
private List mList;
private Context mContext;
public DemoAdapter(Context context, List list) {
mContext = context;
mList = list;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_FOOTER) {
return onCreateFooterViewHolder(parent, viewType);
} else if(viewType == VIEW_TYPE_ITEM) {
return onCreateItemViewHolder(parent, viewType);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case VIEW_TYPE_ITEM:
onBindItemViewHolder(holder, position);
break;
case VIEW_TYPE_FOOTER:
onBindFooterViewHolder(holder, position, mLoadStatus);
break;
default:
break;
}
}
public RecyclerView.ViewHolder onCreateFooterViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.footer_layout, null);
return new FooterViewHolder(view);
}
public RecyclerView.ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.item_layout, null);
return new ItemViewHolder(view);
}
public void onBindFooterViewHolder(RecyclerView.ViewHolder holder, int position, LoadStatus loadStatus) {
FooterViewHolder viewHolder = (FooterViewHolder) holder;
switch (loadStatus) {
case CLICK_LOAD_MORE:
viewHolder.mLoadingLayout.setVisibility(View.GONE);
viewHolder.mClickLoad.setVisibility(View.VISIBLE);
break;
case LOADING_MORE:
viewHolder.mLoadingLayout.setVisibility(View.VISIBLE);
viewHolder.mClickLoad.setVisibility(View.GONE);
break;
}
}
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
ItemViewHolder viewHolder = (ItemViewHolder) holder;
viewHolder.mTextView.setText(getItem(position));
}
@Override
public int getItemCount() {
return mList.size() + 1;
}
public String getItem(int position) {
return mList.get(position);
}
public void addAll(List list) {
this.mList.addAll(list);
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
if(position + 1 == getItemCount()) {//最后一条为FooterView
return VIEW_TYPE_FOOTER;
}
return VIEW_TYPE_ITEM;
}
public void reSetData(List list) {
this.mList = list;
notifyDataSetChanged();
}
public void setLoadStatus(LoadStatus loadStatus) {
this.mLoadStatus = loadStatus;
}
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public ItemViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.textView);
}
}
public class FooterViewHolder extends RecyclerView.ViewHolder {
public LinearLayout mLoadingLayout;
public TextView mClickLoad;
public FooterViewHolder(View itemView) {
super(itemView);
mLoadingLayout = (LinearLayout) itemView.findViewById(R.id.loading);
mClickLoad = (TextView) itemView.findViewById(R.id.click_load_txt);
mClickLoad.setOnClickListener(new View.OnClickListener() {//添加点击加载更多监听
@Override
public void onClick(View v) {
loadMore();
}
});
}
}
public enum LoadStatus {
CLICK_LOAD_MORE,//点击加载更多
LOADING_MORE//正在加载更多
}
6. 写完Adapter的FooterView视图适配之后,我们还有一个重要的步骤需要做,在哪里实现加载更多的逻辑处理
其实RecyclerView也为我们提供了mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() )
接口,这样我们就看一看通过这个接口来判断什么时候调用加载更多的实现接口,关键代码如下:
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) {
loadMore();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
}
});
整个Demo的Activity的实现如下:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private DemoAdapter mAdapter;
private int mLastVisibleItemPosition = 0;
private LinearLayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new DemoAdapter(this, getData("init"));
mRecyclerView.setAdapter(mAdapter);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
final List list = getData("refresh");
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.reSetData(list);
mSwipeRefreshLayout.setRefreshing(false);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
});
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) {
loadMore();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
}
});
}
public void loadMore() {
mAdapter.setLoadStatus(LoadStatus.LOADING_MORE);
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
final List list = getData("load more");
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.addAll(list);
mAdapter.setLoadStatus(LoadStatus.CLICK_LOAD_MORE);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public List getData(String flag) {
int idx = 1;
if(mAdapter != null) {
idx = mAdapter.getItemCount();
}
List list = new ArrayList<>(10);
for(int i = 0; i < 10; i++) {
list.add(flag + ":" + (idx + i));
}
return list;
}
}
以上就是我针对RecyclerView的下拉刷新上拉加载的实现方式。