RecyclerView加载更多(有Foot)

本文介绍了如何在RecyclerView中实现加载更多功能,并添加Footer视图。通过设置布局和进行相关封装,使RecyclerView的Adapter变得更加简洁易用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、设置布局:

RecyclerView的Item的布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:card_view="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="60dp">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        card_view:cardCornerRadius="8dp">

        <TextView
            android:id="@+id/tv_item"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="A"
            android:textColor="#4DB6AC"
            android:textSize="10sp" />

    </android.support.v7.widget.CardView>

</RelativeLayout>
RecyclerView的Foot布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:gravity="center"
              android:orientation="horizontal">

    <ProgressBar
        android:id="@+id/pb_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@drawable/progressbar_refresh" />

    <TextView
        android:id="@+id/tv_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:text="正在加载..."
        android:textColor="#4DB6AC"
        android:textSize="16sp" />

    <LinearLayout
        android:id="@+id/ll_end"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:visibility="gone">

        <View
            android:layout_width="0dp"
            android:layout_height="1dp"
            android:layout_weight="1"
            android:alpha="0.5"
            android:background="#4DB6AC"
            android:gravity="start" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="15dp"
            android:text="大哥已经没有更多的数据"
            android:textColor="#4DB6AC"
            android:textSize="16sp" />

        <View
            android:layout_width="0dp"
            android:layout_height="1dp"
            android:layout_weight="1"
            android:alpha="0.5"
            android:background="#4DB6AC"
            android:gravity="end" />

    </LinearLayout>

</LinearLayout>


2、适配器

/**
 * Created by csc on 2018/4/3.
 * explain:主要实现的是分布局(正常的内容和Foot)
 */

public class LoadMoreAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    //实体数据
    private List<String> mList;

    //普通布局
    private final int TYPE_ITEM=0;
    //脚布局
    private final int TYPE_FOOTER=1;

    //当前加载状态,默认为加载完成
    private int loadState=2;
    //正在加载
    public final int LOADING=1;
    //加载完成
    public final int LOADING_COMPLIETE=2;
    //加载到底
    public final int LOADING_END=3;

    //构造器赋值
    public LoadMoreAdapter(List<String> list) {
        mList = list;
    }

    @Override
    public int getItemViewType(int position) {

        if(position+1 == getItemCount() ){
            //最后一个Item显示脚布局
            return TYPE_FOOTER;
        }else{
            //返回正常的条目
            return TYPE_ITEM;
        }
    }

    //设置布局
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_ITEM){
            View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_recyclerview,parent,false);
            return new RecyclerViewHolder(view);
        }else if (viewType == TYPE_FOOTER){
            View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_refresh_footer,parent,false);
            return new FooterViewHolder(view);
        }
        return null;
    }

    //绑定数据
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof RecyclerViewHolder){
            RecyclerViewHolder itemHolder= (RecyclerViewHolder) holder;
            itemHolder.tvItem.setText(mList.get(position));
        }else if (holder instanceof FooterViewHolder){
            final FooterViewHolder footerViewHolder= (FooterViewHolder) holder;
            switch (loadState){
                //正在加载
                case LOADING:
                    footerViewHolder.pbLoading.setVisibility(View.VISIBLE);
                    footerViewHolder.tvLoading.setVisibility(View.VISIBLE);
                    //设置加载完成布局为隐藏
                    footerViewHolder.llEnd.setVisibility(View.GONE);
                    break;

                //加载完成
                case LOADING_COMPLIETE:
                    footerViewHolder.pbLoading.setVisibility(View.INVISIBLE);
                    footerViewHolder.tvLoading.setVisibility(View.INVISIBLE);
                    footerViewHolder.llEnd.setVisibility(View.GONE);
                    break;

                //加载所有的条目完成
                case LOADING_END:
                    footerViewHolder.pbLoading.setVisibility(View.GONE);
                    footerViewHolder.tvLoading.setVisibility(View.GONE);
                    footerViewHolder.llEnd.setVisibility(View.VISIBLE);
                   /* new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            //1秒以后吧没有更多数据提示隐藏
                            footerViewHolder.llEnd.setVisibility(View.GONE);
                        }
                    },1000);*/
                    break;
                default:
                    break;
            }
        }

    }

    //提供一个方法判断:上来加载的状态
    //0:正在加载 1:加载完成 2:已经没有更多的数据
    public void setLoadState(int loadState){
        this.loadState=loadState;
        notifyDataSetChanged();
    }

    //正常条目的布局类
    private class RecyclerViewHolder extends RecyclerView.ViewHolder{
        private TextView tvItem;
        public RecyclerViewHolder(View itemView) {
            super(itemView);
            tvItem=itemView.findViewById(R.id.tv_item);
        }
    }
    //脚布局
    private class FooterViewHolder extends RecyclerView.ViewHolder{
        private ProgressBar pbLoading;
        private TextView tvLoading;
        private LinearLayout llEnd;

        public FooterViewHolder(View itemView) {
            super(itemView);
            pbLoading=itemView.findViewById(R.id.pb_loading);
            tvLoading=itemView.findViewById(R.id.tv_loading);
            llEnd=itemView.findViewById(R.id.ll_end);
        }
    }


    //总的条目数量
    @Override
    public int getItemCount() {
        //加上脚布局,所以+1
        return mList.size()+1;
    }


    //当网格布局的时候应该是foot居中显示,而不是显示在左边的位置
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager=recyclerView.getLayoutManager();
        //判断是网格布局
        if (manager instanceof GridLayoutManager){
            final GridLayoutManager gridLayoutManager= (GridLayoutManager) manager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    //如果当前是footer的位置
                    //这个footer占据1个单元格
                    return getItemViewType(position) == TYPE_FOOTER?gridLayoutManager.getSpanCount():1;
                }
            });
        }
    }
}


4、逻辑判断Foot的显示隐藏

/**
 * Created by csc on 2018/4/3.
 * explain:在Adapter中设置好FooterView之后,我们需要判断一下什么时候显示出来,
 * 这时就需要对RecyclerView设置一下滑动监听,当滑动到最后一条Item的时候,显示加载更多UI(Footer)
 * 并且开始请求下一个列表数据
 */

abstract class EndLessRecyclerOnScrollListener extends RecyclerView.OnScrollListener{

    //用来记录是否正在向上滑动
    private boolean isSlidingUpward=false;

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        LinearLayoutManager manager= (LinearLayoutManager) recyclerView.getLayoutManager();

        //当前不滑动时
        if(newState == RecyclerView.SCROLL_STATE_IDLE){
            //获取到最后一个完全显示的ItemPosition
            int lastItemPosition=manager.findLastCompletelyVisibleItemPosition();
            //现在总条目数
            int itemCount=manager.getItemCount();
            //判断是否滑动到了最后一个Item,并且向上滑动
            if (lastItemPosition == (itemCount -1) && isSlidingUpward){
                //加载更多
                onLoadMore();
            }
        }
    }

    //判断RecyclerView是否是向上滑动

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        //大于0表示正在向上滑动,小于0表示停止或向下滑动
        isSlidingUpward =dy>0;
    }

    //加载更多的数据回调
    public abstract void onLoadMore();
}

5、设置适配器和监听:

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRv;
    private LoadMoreAdapter mAdapter;

    //假数据
    private List<String> mList;
    //数据的总页数
    private int totalPage=5;
    //当前加载的页数
    private int currentPage=0;
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRv = (RecyclerView) findViewById(R.id.rv);

        initView();
        initData();
        initAdapter();

    }

    private void initView() {
        mRv.setLayoutManager(new LinearLayoutManager(this));
    }

    private void initData() {
        //设置一些假数据
        mList=new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            mList.add("我是假数据"+1);
        }

    }

    private void initAdapter() {
        mAdapter=new LoadMoreAdapter(mList);
        mRv.setAdapter(mAdapter);

        //给RecyclerView设置加载更多监听
        mRv.addOnScrollListener(new EndLessRecyclerOnScrollListener() {
            @Override
            public void onLoadMore() {
                /***************显示正在加载数据的footer****************/
                mAdapter.setLoadState(mAdapter.LOADING);

                //判断加载的页数 等于 总的页数
                if (totalPage == currentPage){
                    /***********************表示数据加载完成************************/
                    mAdapter.setLoadState(mAdapter.LOADING_END);
                }else{
                    //表示去加载更多的数据

                    //模拟一个耗时操作
                    new Timer().schedule(new TimerTask() {
                        @Override
                        public void run() {
                           runOnUiThread(new Runnable() {
                               @Override
                               public void run() {
                                   getMoreData();

                                   /*******************隐藏显示正在加载条目的Footer布局UI************/
                                   mAdapter.setLoadState(mAdapter.LOADING_COMPLIETE);
                               }
                           });
                        }
                    },2000);

                }
            }
        });
    }

    //设置一个添加假数据
    public void getMoreData(){
        currentPage++;
        for (int i = 0; i < 5; i++) {
            mList.add("我是加载更多的数据:"+i+",当前的页数是:"+currentPage);

        }

    }


}

6、运行结果



7、进行封装

public class LoadMoreWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    //普通的布局
    private final int TYPE_ITEM=0;
    //脚布局
    private final int TYPE_FOOTER=1;
    //当前加载状态,默认为加载完成
    private int loadState=2;
    //正在加载
    public final int LOADING=1;
    //加载完成
    public final int LOADING_COMPLETE=2;
    //加载到底
    public final int LOADING_END=3;

    //适配器
   private RecyclerView.Adapter mAdapter;
    public LoadMoreWrapper(RecyclerView.Adapter adapter) {
        mAdapter = adapter;
    }

    //分布局
    @Override
    public int getItemViewType(int position) {
        if (position+1 == getItemCount()){
            return TYPE_FOOTER;
        }else{
            return TYPE_ITEM;
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //进行判断显示类型,来创建还回不同的View
        if (viewType == TYPE_FOOTER){
            View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_refresh_footer,parent,false);
            //还回的是脚布局
            return new FootViewHolder(view);
        }else{
            //还回的是内容的布局
            return mAdapter.onCreateViewHolder(parent,viewType);
        }
    }


   //绑定数据
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof FootViewHolder){
            FootViewHolder footViewHolder= (FootViewHolder) holder;
            switch (loadState){
                //表示正在加载
                case LOADING:
                    footViewHolder.pbLoading.setVisibility(View.VISIBLE);
                    footViewHolder.tvLoading.setVisibility(View.VISIBLE);
                    footViewHolder.llEnd.setVisibility(View.GONE);
                    break;

                //表示加载完成
                case LOADING_COMPLETE:
                    footViewHolder.pbLoading.setVisibility(View.INVISIBLE);
                    footViewHolder.tvLoading.setVisibility(View.INVISIBLE);
                    footViewHolder.llEnd.setVisibility(View.GONE);
                    break;

                //表示加载到底
                case LOADING_END:
                    footViewHolder.pbLoading.setVisibility(View.GONE);
                    footViewHolder.tvLoading.setVisibility(View.GONE);
                    footViewHolder.llEnd.setVisibility(View.VISIBLE);
                    break;
                default:
                    break;
            }
        }else{
            mAdapter.onBindViewHolder(holder,position);
        }

    }

    //总的条目数量
    @Override
    public int getItemCount() {
        return mAdapter.getItemCount()+1;
    }

    //脚布局
    private class FootViewHolder extends RecyclerView.ViewHolder{
        ProgressBar pbLoading;
        TextView tvLoading;
        LinearLayout llEnd;
        public FootViewHolder(View itemView) {
            super(itemView);
            pbLoading=itemView.findViewById(R.id.pb_loading);
            tvLoading=itemView.findViewById(R.id.tv_loading);
            llEnd=itemView.findViewById(R.id.ll_end);
        }
    }


    //当时网格布局的时候Foot需要居中显示
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager=recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager){
            final GridLayoutManager gridLayoutManager= (GridLayoutManager) manager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    //如果是脚布局据合并单元格
                    return getItemViewType(position)==TYPE_FOOTER?1:gridLayoutManager.getSpanCount();
                }
            });
        }
    }

    //设置上拉的时候改变对应的状态
    public void setLoadState(int loadState){
        this.loadState=loadState;
        notifyDataSetChanged();
    }
}

我们乍一眼看和上面的LoadMoreAdapter没有什么区别,都是继承了RecyclerView.Adapter并且实现了其中的一些方法,但是我们仔细看会发现,构造器中的参数变成了RecyclerView.Adapter,在LoadMoreWrapper中我们只处理加载更多功能相关的逻辑,其他逻辑都交给Adapter本身去处理,相当于扩展了Adapter的一些功能,这种方式还有一个学名叫【装饰者模式】

封装以后的Rv的Adapter变成这样:

public class LoadMoreWrapperAdaoter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    //数据
    private List<String> mList;

    public LoadMoreWrapperAdaoter(List<String> list) {
        this.mList = list;
    }

    //加载内容布局
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_recyclerview,parent,false);
        RecyclerViewHolder recyclerViewHolder=new RecyclerViewHolder(view);
        return recyclerViewHolder;
    }

    //绑定内容的数据
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        RecyclerViewHolder recyclerViewHolder= (RecyclerViewHolder) holder;
        System.out.println("当前的条目数据为:"+mList.get(position));

        recyclerViewHolder.tvItem.setText(mList.get(position));

    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    //Adapter的内容布局
    private class RecyclerViewHolder extends RecyclerView.ViewHolder{
        TextView tvItem;

        public RecyclerViewHolder(View itemView) {
            super(itemView);
            tvItem=itemView.findViewById(R.id.tv_item);
        }
    }
}

然后就是给RecyclerView设置适配器:

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRv;


    //假数据
    private List<String> mList;
    //数据的总页数
    private int totalPage = 5;
    //当前加载的页数
    private int currentPage = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRv = (RecyclerView) findViewById(R.id.rv);

        initView();
        initData();
        initAdapter();

    }

    private void initView() {
        mRv.setLayoutManager(new LinearLayoutManager(this));
    }

    private void initData() {
        //设置一些假数据
        mList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            mList.add("我是假数据" + 1);
        }

    }


    LoadMoreWrapper mAdapter;
    private void initAdapter() {
        /*******************主要的改变*********************/
       //就是在原有Adapter的基础上包上一层
        LoadMoreWrapperAdaoter loadMoreWraooerAdaoter = new LoadMoreWrapperAdaoter(mList);
        mAdapter = new LoadMoreWrapper(loadMoreWraooerAdaoter);
        mRv.setAdapter(mAdapter);

        
        //给RecyclerView设置加载更多监听
        mRv.addOnScrollListener(new EndLessRecyclerOnScrollListener() {
            @Override
            public void onLoadMore() {
                /***************显示正在加载数据的footer****************/
                mAdapter.setLoadState(mAdapter.LOADING);

                //判断加载的页数 等于 总的页数
                if (totalPage == currentPage) {
                    /***********************表示数据加载完成************************/
                    mAdapter.setLoadState(mAdapter.LOADING_END);
                } else {
                    //表示去加载更多的数据

                    //模拟一个耗时操作
                    new Timer().schedule(new TimerTask() {
                        @Override
                        public void run() {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    getMoreData();

                                    /*******************隐藏显示正在加载条目的Footer布局UI************/
                                    mAdapter.setLoadState(mAdapter.LOADING_COMPLETE);
                                }
                            });
                        }
                    }, 2000);

                }
            }
        });
    }

    //设置一个添加假数据
    public void getMoreData() {
        currentPage++;
        for (int i = 0; i < 5; i++) {
            mList.add("我是加载更多的数据:" + i + ",当前的页数是:" + currentPage);

        }

    }


}





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值