上拉、下拉的效果图如下:
使用步骤
- 1、在清单文件中添加依赖
implementation ‘com.android.support:recyclerview-v7:27.1.1’
implementation “androidx.swiperefreshlayout:swiperefreshlayout:1.0.0”
- 2、main布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
- item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:textSize="20sp"
android:textColor="#000000"
android:text="11"
android:layout_marginBottom="1dp"/>
</LinearLayout>
- footview.xml(底部提示)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="20dp"
android:textSize="15sp"
android:layout_marginBottom="1dp"/>
</LinearLayout>
- 2、MyAdapter
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<String> datas; // 数据源
private Context context; // 上下文Context
private int normalType = 0; // 第一种ViewType,正常的item
private int footType = 1; // 第二种ViewType,底部的提示View
private boolean hasMore = true; // 变量,是否有更多数据
private boolean fadeTips = false; // 变量,是否隐藏了底部的提示
private Handler mHandler = new Handler(Looper.getMainLooper()); //获取主线程的Handler
public MyAdapter(List<String> datas, Context context, boolean hasMore) {
// 初始化变量
this.datas = datas;
this.context = context;
this.hasMore = hasMore;
}
// 获取条目数量,之所以要加1是因为增加了一条footView
@Override
public int getItemCount() {
return datas.size() + 1;
}
// 自定义方法,获取列表中数据源的最后一个位置,比getItemCount少1,因为不计上footView
public int getRealLastPosition() {
return datas.size();
}
// 根据条目位置返回ViewType,以供onCreateViewHolder方法内获取不同的Holder
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return footType;
} else {
return normalType;
}
}
// 正常item的ViewHolder,用以缓存findView操作
class NormalHolder extends RecyclerView.ViewHolder {
private TextView textView;
public NormalHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.tv);
}
}
// // 底部footView的ViewHolder,用以缓存findView操作
class FootHolder extends RecyclerView.ViewHolder {
private TextView tips;
public FootHolder(View itemView) {
super(itemView);
tips = (TextView) itemView.findViewById(R.id.tips);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 根据返回的ViewType,绑定不同的布局文件,这里只有两种
if (viewType == normalType) {
return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.item, null));
} else {
return new FootHolder(LayoutInflater.from(context).inflate(R.layout.footview, null));
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
// 如果是正常的imte,直接设置TextView的值
if (holder instanceof NormalHolder) {
((NormalHolder) holder).textView.setText(datas.get(position));
} else {
// 之所以要设置可见,是因为我在没有更多数据时会隐藏了这个footView
((FootHolder) holder).tips.setVisibility(View.VISIBLE);
// 只有获取数据为空时,hasMore为false,所以当我们拉到底部时基本都会首先显示“正在加载更多...”
if (hasMore == true) {
// 不隐藏footView提示
fadeTips = false;
if (datas.size() > 0) {
// 如果查询数据发现增加之后,就显示正在加载更多
((FootHolder) holder).tips.setText("正在加载更多...");
}
} else {
if (datas.size() > 0) {
// 如果查询数据发现并没有增加时,就显示没有更多数据了
((FootHolder) holder).tips.setText("没有更多数据了");
// 然后通过延时加载模拟网络请求的时间,在500ms后执行
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// 隐藏提示条
((FootHolder) holder).tips.setVisibility(View.GONE);
// 将fadeTips设置true
fadeTips = true;
// hasMore设为true是为了让再次拉到底时,会先显示正在加载更多
hasMore = true;
}
}, 500);
}
}
}
}
// 暴露接口,改变fadeTips的方法
public boolean isFadeTips() {
return fadeTips;
}
// 暴露接口,下拉刷新时,通过暴露方法将数据源置为空
public void resetDatas() {
datas = new ArrayList<>();
}
// 暴露接口,更新数据源,并修改hasMore的值,如果有增加数据,hasMore为true,否则为false
public void updateList(List<String> newDatas, boolean hasMore) {
// 在原有的数据之上增加新数据
if (newDatas != null) {
datas.addAll(newDatas);
}
this.hasMore = hasMore;
notifyDataSetChanged();
}
}
- 3、MainActivity实现
public class MainActivity extends AppCompatActivity{
private SwipeRefreshLayout refreshLayout;
private RecyclerView recyclerView;
private List<String> list;
private int lastVisibleItem = 0;
private final int COUNT = 10;
private GridLayoutManager mLayoutManager;
private MyAdapter adapter;
private Handler mHandler = new Handler(Looper.getMainLooper());
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();//制造假数据
initView();//初始化布局
initRefreshLayout();//初始化下拉刷新
initRecyclerView();//显示recyclerview布局
}
private void initData() {
list = new ArrayList<>();
for (int i = 1; i <= 40; i++) {
list.add("测试" + i);
}
}
private void initView() {
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refreshLayout);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
}
private void initRefreshLayout() {
refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {//上拉刷新,加载第一页
refreshLayout.setRefreshing(true);
adapter.resetDatas();
updateRecyclerView(0, COUNT);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
refreshLayout.setRefreshing(false);
}
}, 1000);
}
});
}
private void initRecyclerView() {
adapter = new MyAdapter(getDatas(0, COUNT), this, getDatas(0, COUNT).size() > 0 ? true : false);
mLayoutManager = new GridLayoutManager(this, 1);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + COUNT);
}
}, 500);
}
if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + COUNT);
}
}, 500);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
}
});
}
private void updateRecyclerView(int fromIndex, int toIndex) {
List<String> newDatas = getDatas(fromIndex, toIndex);
if (newDatas.size() > 0) {
adapter.updateList(newDatas, true);
} else {
adapter.updateList(null, false);
}
}
//拿到全部数据,加载
private List<String> getDatas(final int firstIndex, final int lastIndex) {
List<String> resList = new ArrayList<>();
for (int i = firstIndex; i < lastIndex; i++) {
if (i < list.size()) {
resList.add(list.get(i));
}
}
return resList;
}
}