Android RecyclerView实现上拉加载、分页 功能--拿来就能用

对初学者来说这简直。。。,网上例子找了一大堆,最后终于有了结果,现做记录留个笔记,自己参考

activity_recycler_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".RecyclerViewActivity">



    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/sr_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</LinearLayout>
rv_recyclerview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp">
    <TextView
        android:id="@+id/tv_recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="data"
        android:background="#cac3c3"
        android:padding="10dp"
        android:textSize="20sp"/>
</LinearLayout>
rv_recyclerview_item_footer.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal">
    <ProgressBar
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:id="@+id/pb_footer_progressBar" />
    <TextView
        android:text="正在努力加载中,请稍后..."
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:id="@+id/tv_footer" />
</LinearLayout>
下面是这个RecyclerViewActivity.java代码
package com.example.demo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zpn
 * @date 2020-09-24
 */
public class RecyclerViewActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    private RecyclerView rv_recyclerview;
    private SwipeRefreshLayout sr_layout;
    private LinearLayoutManager mLayoutManager;

    private List<String> list;
    private MyAdapter adapter;

    private int lastVisibleItem = 0;
    private final int PAGE_COUNT = 10;

    private Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);
        sr_layout = findViewById(R.id.sr_layout);
        rv_recyclerview = findViewById(R.id.rv_recyclerview);
        initData();
        initRefreshLayout();
        initRecyclerView();
    }

    private void initData() {
        list = new ArrayList<>();
        for (int i = 1; i <= 40; i++) {
            list.add("条目" + i);
        }
    }

    private void initRefreshLayout() {
        //sr_layout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
          //      android.R.color.holo_orange_light, android.R.color.holo_green_light);
        sr_layout.setOnRefreshListener(this);
    }

    private void initRecyclerView() {
        adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);
        mLayoutManager = new LinearLayoutManager(this);
        rv_recyclerview.setLayoutManager(mLayoutManager);
        rv_recyclerview.setAdapter(adapter);
        rv_recyclerview.setItemAnimator(new DefaultItemAnimator());

        rv_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() + PAGE_COUNT);
                            }
                        }, 500);
                    }

                    if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
                            }
                        }, 500);
                    }
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
            }
        });
    }

    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;
    }

    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);
        }
    }

    @Override
    public void onRefresh() {
        sr_layout.setRefreshing(true);
        adapter.resetDatas();
        updateRecyclerView(0, PAGE_COUNT);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                sr_layout.setRefreshing(false);
            }
        }, 1000);
    }


    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; // 变量,是否隐藏了底部的提示

        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_recycler);
            }
        }

        // // 底部footView的ViewHolder,用以缓存findView操作
        class FootHolder extends RecyclerView.ViewHolder {
            private TextView tips;
            private ProgressBar pb_footer_progressBar;

            public FootHolder(View itemView) {
                super(itemView);
                tips = (TextView) itemView.findViewById(R.id.tv_footer);
                pb_footer_progressBar = (ProgressBar)itemView.findViewById(R.id.pb_footer_progressBar);
            }
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            // 根据返回的ViewType,绑定不同的布局文件,这里只有两种
            if (viewType == normalType) {
                return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.rv_recyclerview_item, parent,false));
            } else {
                return new FootHolder(LayoutInflater.from(context).inflate(R.layout.rv_recyclerview_item_footer, parent,false));
            }
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
            // 如果是正常的imte,直接设置TextView的值
            if (holder instanceof NormalHolder) {
                ((NormalHolder) holder).textView.setText(datas.get(position));
            } else {
                if(getItemCount() < PAGE_COUNT){
                    ((FootHolder) holder).tips.setVisibility(View.GONE);
                    ((FootHolder) holder).pb_footer_progressBar.setVisibility(View.GONE);
                }else {
                    // 之所以要设置可见,是因为我在没有更多数据时会隐藏了这个footView
                    ((FootHolder) holder).tips.setVisibility(View.VISIBLE);
                    ((FootHolder) holder).pb_footer_progressBar.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);
                                    ((FootHolder) holder).pb_footer_progressBar.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();
        }

    }



}

 

 

 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,RecyclerView是一个强大的UI组件,用于显示大量数据列表。当我们需要显示大量数据时,通常会需要进行分页加载实现上拉加载更多的功能。 下面是实现RecyclerView上拉加载更多的一般步骤: 1. 在RecyclerView的Adapter中添加一个Footer View,用于显示“正在加载中”或“没有更多数据”等提示信息。 2. 监听RecyclerView的滚动事件,当滚动到底部时,显示Footer View,并开始加载更多数据。 3. 加载更多数据时,更新RecyclerView的数据源并刷新Adapter。同时,隐藏Footer View。 下面是一个简单的实现代码: 1. 添加Footer View ```java public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final int TYPE_ITEM = 0; private static final int TYPE_FOOTER = 1; private boolean mShowFooter = true; // 是否显示Footer,默认显示 // ... // 在创建ViewHolder时,判断是否为Footer View @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_FOOTER) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.footer_view, parent, false); return new FooterViewHolder(view); } // ... } // 在绑定ViewHolder时,根据位置判断是否为Footer View @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof FooterViewHolder) { FooterViewHolder footerHolder = (FooterViewHolder) holder; if (mShowFooter) { footerHolder.mFooterView.setVisibility(View.VISIBLE); } else { footerHolder.mFooterView.setVisibility(View.GONE); } } else { // ... } } // 返回ItemType @Override public int getItemViewType(int position) { if (!mShowFooter) { return TYPE_ITEM; } if (position == getItemCount() - 1) { return TYPE_FOOTER; } return TYPE_ITEM; } // 显示或隐藏Footer View public void showFooter(boolean show) { mShowFooter = show; notifyDataSetChanged(); } // Footer ViewHolder public static class FooterViewHolder extends RecyclerView.ViewHolder { public View mFooterView; public FooterViewHolder(View itemView) { super(itemView); mFooterView = itemView; } } } ``` 2. 监听RecyclerView滚动事件 ```java mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { // 是否正在向上滑动 private boolean isSlidingUpward = false; @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { // 当滚动停止时 LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); // 最后一个完全可见的item的位置 int lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition(); int totalItemCount = layoutManager.getItemCount(); // 判断是否滚动到底部,并且不是正在向上滑动 if (lastVisibleItem == (totalItemCount - 1) && isSlidingUpward) { // 加载更多数据 // ... } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 判断是否正在向上滑动 isSlidingUpward = dy > 0; } }); ``` 3. 加载更多数据 ```java private int currentPage = 1; private boolean isLoading = false; private void loadMoreData() { if (isLoading) { return; } isLoading = true; // 显示Footer View mAdapter.showFooter(true); // 加载数据 // ... // 更新数据源 // ... // 刷新Adapter mAdapter.notifyDataSetChanged(); // 隐藏Footer View mAdapter.showFooter(false); isLoading = false; currentPage++; } ``` 以上是RecyclerView上拉加载更多的一般实现步骤,具体实现可能会因为业务需求有所不同,但是以上步骤可以为你提供一个基本的思路。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值