SwipeRefreshLayout 是谷歌公司推出的用于下拉刷新的控件,在Version 19.1之后SwipeRefreshLayout 被放到support v4中。我们在前面也已经说过一个SwipeRefreshLayout和ListView实现上拉加载、下拉刷新的例子。而现在RecyclerView也已作为实现列表功能的首选组件,而它本身并没有实现上拉加载、下拉刷新的功能,本节我们就来利用SwipeRefreshLayout 和RecyclerView来实现上拉加载、下拉刷新的功能。
SwipeRefreshLayout 常用的方法如下:
- setOnRefreshListener(OnRefreshListener):下拉刷新监听器,当用户下拉的时候会触发
- setRefreshing(boolean):设置SwipeRefreshLayout当前是否处于刷新状态,一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。
- isRefreshing():检查是否处于刷新状态
- setColorSchemeResources():设置进度条的颜色主题,最多设置四种,以前的setColorScheme()方法已经弃用了。
- setProgressViewOffset(boolean scale, int start, int end) 调整进度条距离屏幕顶部的距离
布局文件很简单
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.xmr.recycleandswiperefresh.MainActivity">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/ryv_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
接着在Activity中获取SwipeRefreshLayout控件并且设置OnRefreshListener监听器,同时实现里边的onRefresh()方法,在该方法中进行网络请求最新数据,然后刷新RecyclerView列表同时设置SwipeRefreshLayout的显示效果。具体代码如下:
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//实际项目中这里一般是用网络请求获取数据
mList.add("下拉刷新");
mAdapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
}
});
RecyclerView的实现:
第一种,下拉刷新和上拉刷新都用SwipeRefreshLayout 自带的效果
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView,
int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& lastVisibleItem + 1 == mAdapter.getItemCount()) {
mSwipeRefreshLayout.setRefreshing(true);
//实际项目中这里一般是用网络请求获取数据
mList.add("上拉加载");
//为了有刷新的效果,延迟关闭刷新效果
mSwipeRefreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
mAdapter.notifyDataSetChanged();
}
}, 2000);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//判断是当前layoutManager是否为LinearLayoutManager
// 只有LinearLayoutManager才有查找第一个和最后一个可见view位置的方法
if (linearLayoutManager instanceof LinearLayoutManager) {
//获取最后一个可见view的位置
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
//获取第一个可见view的位置
// int firstItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
}
}
});
效果如下:
第二种实现下拉刷新用SwipeRefreshLayout 自带的效果, 上拉加载我们可以给RecyclerView 添加一个类似FooterView的item。
我们在Adapter中实现:
package com.xmr.recycleandswiperefresh;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
/**
* Created by Administrator on 2016/9/13.
*/
public class RefreshAdapter1 extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<String> mDatas;
private static final int TYPE_ITEM = 0; //普通Item View
private static final int TYPE_FOOTER = 1; //底部FootView
//已经到底了
public static final int PULLUP_LOAD_MORE = 0;
//正在加载中
public static final int LOADING_MORE = 1;
//上拉加载状态-默认为0
private int load_more_status = 0;
public RefreshAdapter1(Context mContext, List<String> mDatas) {
this.mContext = mContext;
this.mDatas = mDatas;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//进行判断显示类型,来创建返回不同的View
if (viewType == TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_recycler_refresh, null);
// view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
// LayoutParams.WRAP_CONTENT));
return new ItemHolder(view);
}
// type == TYPE_FOOTER 返回footerView
else if (viewType == TYPE_FOOTER) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_recycler_footer, null);
// view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
// LayoutParams.WRAP_CONTENT));
return new FooterHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ItemHolder) {
ItemHolder itemHolder = (ItemHolder) holder;
itemHolder.textView.setText(mDatas.get(position));
} else if (holder instanceof FooterHolder) {
FooterHolder footHolder = (FooterHolder) holder;
//这句如果不注释,那么底部就会有添加的一个item
footHolder.linearLayout.setVisibility(View.GONE);
switch (load_more_status) {
case PULLUP_LOAD_MORE:
footHolder.linearLayout.setVisibility(View.GONE);
// footHolder.textView.setText("已经到底了");
break;
case LOADING_MORE:
footHolder.linearLayout.setVisibility(View.VISIBLE);
footHolder.textView.setText("正在加载更多数据...");
break;
}
}
}
@Override
public int getItemCount() {
return mDatas == null ? 0 : mDatas.size() + 1;
}
@Override
public int getItemViewType(int position) {
// 最后一个item设置为footerView
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
class ItemHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ItemHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.tv_item_recycler_refresh);
}
}
class FooterHolder extends RecyclerView.ViewHolder {
public TextView textView;
public LinearLayout linearLayout;
public FooterHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.tv_item_recycler_footer);
linearLayout = (LinearLayout) itemView.findViewById(R.id.ll_item_recycler_footer);
}
}
/**
* //上拉加载更多
* PULLUP_LOAD_MORE=0;
* //正在加载中
* LOADING_MORE=1;
* //加载完成已经没有更多数据了
* NO_MORE_DATA=2;
*
* @param status
*/
public void changeMoreStatus(int status) {
load_more_status = status;
notifyDataSetChanged();
}
}
而对RecyclerView的上拉加载,我们这样实现:
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView,
int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& lastVisibleItem + 1 == mAdapter.getItemCount()) {
Log.i(">>>>>", ">>>>" + lastVisibleItem + ">>>" + mAdapter.getItemCount());
mAdapter.changeMoreStatus(mAdapter.LOADING_MORE);
//为了有刷新的效果,延迟2s修改状态
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mAdapter.changeMoreStatus(RefreshAdapter1.PULLUP_LOAD_MORE);
//实际项目中这里一般是用网络请求获取数据
mList.add("上拉加载");
}
}, 2000);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//判断是当前layoutManager是否为LinearLayoutManager
// 只有LinearLayoutManager才有查找第一个和最后一个可见view位置的方法
if (linearLayoutManager instanceof LinearLayoutManager) {
//获取最后一个可见view的位置
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
//获取第一个可见view的位置
// int firstItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
}
}
});
}
最终效果如下:
不过,现在也有点bug,如果列表没有占满屏幕的话,下拉刷新的时候也会同时触发上拉加载的效果,大家如果有好的解决方案的话可以给我说下,先谢谢了