android的SwipeRefreshLayout+RecycleView实现上拉加载下拉刷新

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Wengwuhua/article/details/84729740

介绍

本文主要实现的是上拉加载更多功能,下拉刷新使用的是Google官方的SwipeRefreshLayout控件,但是却没有实现上拉加载。我们一般用到上拉加载功能都是在列表显示中,所以本文用SwipeRefreshLayout配合RecycleView实现上拉加载和下拉刷新功能。

实现

下拉刷新我们用SwipeRefreshLayout原生的能力即可,主要是如何实现上拉加载呢?简单的实现思路如下:通过监听RecycleView的上拉操作,在其滚动监听状态中判断当前显示的item是不是最后一个item从而决定是否调用加载更多操作。
首先看主布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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="com.demo.wong.myrefreshandloadrecycleview.MainActivity">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
        >
        </android.support.v7.widget.RecyclerView>
    </android.support.v4.widget.SwipeRefreshLayout>

</android.support.constraint.ConstraintLayout>

在RecyclerView外层套一个SwipeRefreshLayout即可
接着item的布局

<?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"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margin="10dp"
    >
    
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:background="@color/cardview_dark_background"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:cardCornerRadius="10dp"
        android:elevation="10dp">
        <TextView
            android:id="@+id/tvContent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="item"
            android:textColor="@color/colorAccent"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:textSize="20sp"/>
    </android.support.v7.widget.CardView>

</LinearLayout>

footer的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        >
        <ProgressBar
            android:id="@+id/progressBar"
            style="?android:attr/progressBarStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />

        <TextView
            android:id="@+id/tvMsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:textColor="@color/colorAccent"
            android:text="加载中..."
            />
    </LinearLayout>

    <TextView
        android:id="@+id/tvBottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="@color/colorAccent"
        android:textSize="20sp"
        android:text="------我是有底线的------"/>

</LinearLayout>

下面就是主要的部分,adapter的实现了,代码里的注释都比较清晰了。

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

    private ArrayList<String> mDatas;

    private final int ITEM_TYPE =0; //item布局类型
    private final int FOOTER_TYPPE = 1; //footer布局类型
    public static final int LOADING = 0; //加载中
    public static final int LOAD_FINISH = 1; //加载完成
    public static final int LOAD_END =2;  //加到底

    private int loadState = LOAD_FINISH;

    public RefreshLoadRecycleAdapter( ArrayList<String> datas){
        mDatas = datas;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(viewType == FOOTER_TYPPE){
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.footer_layout,parent,false);
            return new FooterViewHolder(view);
        }else if(viewType == ITEM_TYPE){
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout,parent,false);
            return new ItemViewHolder(view);
        }
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof ItemViewHolder){
            ItemViewHolder itemViewHolder = (ItemViewHolder)holder;
            itemViewHolder.tvContent.setText(mDatas.get(position));
        }else if(holder instanceof FooterViewHolder){
            FooterViewHolder footerViewHolder = (FooterViewHolder)holder;
            if(loadState == LOADING){
                footerViewHolder.mProgressBar.setVisibility(View.VISIBLE);
                footerViewHolder.tvMsg.setVisibility(View.VISIBLE);
                footerViewHolder.tvBottom.setVisibility(View.GONE);
            }else if(loadState == LOAD_FINISH){
                footerViewHolder.mProgressBar.setVisibility(View.INVISIBLE);
                footerViewHolder.tvMsg.setVisibility(View.INVISIBLE);
                footerViewHolder.tvBottom.setVisibility(View.GONE);
            }else if(loadState == LOAD_END){
                footerViewHolder.mProgressBar.setVisibility(View.GONE);
                footerViewHolder.tvMsg.setVisibility(View.GONE);
                footerViewHolder.tvBottom.setVisibility(View.VISIBLE);
            }
        }
    }

    @Override
    public int getItemCount() {
        return mDatas.size() + 1;  //加一个footer布局
    }

    @Override
    public int getItemViewType(int positon){
        if(positon + 1 == getItemCount()){  //最后一个为footer布局
            return FOOTER_TYPPE;
        }
        return ITEM_TYPE;
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        //适配gridiew 的情况
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    // 如果当前是footer的位置,那么该item占据n个单元格,正常情况下占据1个单元格
                    return getItemViewType(position) == FOOTER_TYPPE ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    //添加刷新数据
    public void AddHeaderItem(ArrayList<String> items){
        mDatas.addAll(0,items);
        notifyDataSetChanged();
    }

    //添加加载数据
    public void AddFooterItem(ArrayList<String> items){
        mDatas.addAll(items);
        notifyDataSetChanged();
    }

    /**
     * 设置加载状态
     * @param loadState
     */
    public void setLoadState(int loadState) {
        this.loadState = loadState;
        notifyDataSetChanged();
    }

    //item 布局holder
    static class ItemViewHolder extends RecyclerView.ViewHolder{

        TextView tvContent;

        public ItemViewHolder(View itemView) {
            super(itemView);
            tvContent = itemView.findViewById(R.id.tvContent);
        }
    }
    //footer 布局holder
    static class FooterViewHolder extends RecyclerView.ViewHolder{

        ProgressBar mProgressBar;
        TextView tvMsg;
        TextView tvBottom;

        public FooterViewHolder(View itemView) {
            super(itemView);
            mProgressBar = itemView.findViewById(R.id.progressBar);
            tvMsg = itemView.findViewById(R.id.tvMsg);
            tvBottom = itemView.findViewById(R.id.tvBottom);
        }
    }
}

接着要实现RecycleView的滑动监听,判断滑动状态实现上拉刷新.这里用抽象类继承 RecyclerView.OnScrollListener来实现

public abstract class RecycleOnscrollListener extends RecyclerView.OnScrollListener{
    //用来标记是否正在向上滑动
    private boolean isSlidingUp = 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) && isSlidingUp) {
                //加载更多
                onLoadMore();
            }
        }
    }

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

    /**
     * 加载更多回调
     */
    public abstract void onLoadMore();

使用

前期的实现都完成了,下面看怎么使用.其实主要就是实现两个监听,下拉刷新( mRefreshLayout.setOnRefreshListener)和上拉( recyclerView.addOnScrollListener)

private SwipeRefreshLayout mRefreshLayout;
    private RecyclerView recyclerView;
    private RefreshLoadRecycleAdapter mRecycleAdapter;
    private ArrayList<String> dataList = new ArrayList<>();

    private int page =  0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRefreshLayout = findViewById(R.id.refreshLayout);
        recyclerView = findViewById(R.id.recyclerView);

        //进度条圈圈颜色
        mRefreshLayout.setColorSchemeColors(Color.RED,Color.BLUE,Color.GREEN);
       // mRefreshLayout.setColorSchemeResources(R.color.colorAccent);

        init();
    }

    private void init(){
        page = 0;
        getData(page);
        mRecycleAdapter = new RefreshLoadRecycleAdapter(dataList);
        recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        //自定义分割线
       // recyclerView.addItemDecoration(new RecycleViewDivider(this, RecycleViewDivider.LIST_VERTICAL));
        recyclerView.setAdapter(mRecycleAdapter);

        initListener();

    }

    private void initListener(){
        //上拉加载
        recyclerView.addOnScrollListener(new RecycleOnscrollListener(){

            @Override
            public void onLoadMore() {
                mRecycleAdapter.setLoadState(RefreshLoadRecycleAdapter.LOADING);

                if (dataList.size() <= 60) {
                    // 模拟获取网络数据,延时3s
                    new Timer().schedule(new TimerTask() {
                        @Override
                        public void run() {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    page++;
                                    getData(page);
                                    mRecycleAdapter.setLoadState(mRecycleAdapter.LOAD_FINISH);
                                }
                            });
                        }
                    }, 3000);
                } else {
                    // 显示加载到底的提示
                    page = 0;
                    mRecycleAdapter.setLoadState(mRecycleAdapter.LOAD_END);
                }
            }
        });

        //下拉刷新
        mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        ArrayList<String> headDatas = new ArrayList<String>();
                        for (int i = 0; i <20 ; i++) {

                            headDatas.add("Heard Item "+i);
                        }
                        mRecycleAdapter.AddHeaderItem(headDatas);

                        //刷新完成
                        mRefreshLayout.setRefreshing(false);   //一定记得set,不然刷新动画一直在
                        Toast.makeText(MainActivity.this, "更新了 "+headDatas.size()+" 条目数据", Toast.LENGTH_SHORT).show();
                    }

                }, 3000);
            }
        });
    }
    private void getData(int page){
        int ind = 20 * page;
        ArrayList<String> datas = new ArrayList<>();
        for (int i = ind; i < 20 + ind; i++) {
            datas.add("item " + i);
        }
        if(page ==0) {
            dataList.addAll(datas);
        }else {
            mRecycleAdapter.AddFooterItem(datas);
        }
    }

效果图:
下拉刷新
在这里插入图片描述
上拉加载
在这里插入图片描述

参考https://www.jianshu.com/p/b502c5b59998
另外github有大神实现了一个比较多功能的RecyclerView侧滑菜单,Item拖拽,滑动删除Item,自动加载更多等的开源项目,有兴趣可以看看https://github.com/yanzhenjie/SwipeRecyclerView

猜你喜欢

转载自blog.csdn.net/Wengwuhua/article/details/84729740