RecyclerView系列之(3):添加下拉刷新和上拉加载更多

本文详细介绍如何在Android应用中为RecyclerView实现下拉刷新及上拉加载更多功能。利用SwipeRefreshLayout实现下拉刷新效果,通过监听滚动事件实现上拉加载。文章提供了完整的代码示例。

今天终于有点时间,来写了一下: 为RecyclerView实现下拉刷新和上拉加载更多。今天会在前面的两篇文章的基础上:
RecyclerView系列之(1):为RecyclerView添加Header和Footer
RecyclerView系列之(2):为RecyclerView添加分隔线
继续讲述RecyclerView中一些常用组件的实现下拉刷新和上拉加载更多的功能。
在现在的Android手机应用中,几乎每一个APP都有下拉刷新和上拉加载更多的功能,它们的重要性不言而喻。

先不多说,先看效果图:


下拉刷新效果图

上拉加载更多效果图

下拉刷新和上拉加载这两个功能,一开始给人的感觉就是它们是一个组合,它们之间是不是存在什么关系,但是事实上,实现的方式是完全不一样的。下面我将结合核心部分代码来讲一下它们的实现。


一. 实现下拉刷新

在google的android.support.v4包中,提供一个SwipeRefreshLayout方法, 用于实现下拉刷新,实现的过程也非常简单, 那我们先来看一下SwipeRefreshLayout是什么东西,其实从名字上来看,它就是一个刷新布局,我们来看它的继承结构图:


SwipeRefreshLayout的继承结构图

从上面的继承结构可以看出, 它继承于:ViewGroup. 而我们常见的LinearLayout, GridLayout等常见的布局,也是继承于ViewGroup。所以它的使用方法和我们常见的差不多,我们想要刷新下拉刷新我们的RecyclerView, 那我们就要将我们的RecyclerView布局文件放到SwipeLayout中。


而在SwipeRefleshLayout中,它又提供了一个接口:SwipeRefreshLayout.OnRefreshListener, 并且在这个口里面提供了一个抽象方法:onRefresh(), 到这里, 我们大概知道它是怎么运作的了,我们只需要在Activity中,实现这个接口,并且实现OnRefresh()方法即可,在onReflesh()方法中,进行我们的刷新数据操作,下面直接来看主要代码:

在主布局中的文件:加入以下代码:

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/layout_swipe_refresh"
    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>

就是SwipeRefreshLayout中包含我们的recyclerView


在Activity中
实现以下核心代码:

  1. 创建一个SwipeRefreshLayout对象,在onCreate()方法中初始化
    mRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.layout_swipe_refresh);
  2. 为其添加SwipeRefreshLayout.OnRefreshListener事件:
mRefreshLayout.setOnRefreshListener(new OnRefreshListener(){
    public void onRefresh() {
         //我在List最前面加入一条数据
        mData.add(0, "嘿,我是“下拉刷新”生出来的");

        //数据重新加载完成后,提示数据发生改变,并且设置现在不在刷新
        mAdapter.notifyDataSetChanged();
        mRefreshLayout.setRefreshing(false);
    }
});

到这里,就实现了下拉刷新的功能,具体的Adapter的实现,分隔线的加入,请看我前面的两篇文章,或者是看后面附带的源码
这样,我们就实现了下拉刷新的功能,下面再来实现上拉加载更多的功能。


二. 上拉加载更多

上拉加载,主要实现的是一个类似分页的功能,不能一开始的时候就加载全部数据,如果数据很多,或者是网络速度慢的话,这需要很久的时间才能加载完成。而上拉加载的思想是:我一开始的时候,就给你加载二十条数据左右,如果你还想看下面的数据的画,再次进行加载二十条,分批次加载,这样就提升了用户体验。


public class MainActivity extends AppCompatActivity {

    List<Integer> data=new ArrayList<Integer>();
    SwipeRefreshLayout swipeRefreshLayout;
    RecyclerView recyclerView;
    MyAdapter adapter;
    boolean flag=true;  //数据是否更新完成的标志
    LinearLayoutManager layoutManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        swipeRefreshLayout=(SwipeRefreshLayout)findViewById(R.id.swipe);
        recyclerView=(RecyclerView)findViewById(R.id.recycler);
        initData();
        layoutManager=new LinearLayoutManager(MainActivity.this);
        //linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);   //要在setAdapter之前setLayoutManager
        adapter=new MyAdapter(data);
        recyclerView.setAdapter(adapter);
        /**
         * 上拉加载功能的实现
         */
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            int number=20;  //下一次更新的数据条数
            int maxpage=5;  //更新的总的最大页数
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }
            //每下拉一部分就执行onScrolled的方法
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int visibleTotal=layoutManager.getChildCount();     //整个屏幕内可视item的条数
                int itemTotal=layoutManager.getItemCount();         //总的item的数量
                int firstItemPosition=layoutManager.findFirstVisibleItemPosition();//可视的第一个item的位置
                //判断是否下拉至最底部并且数据更新完成
                if (firstItemPosition+visibleTotal>=itemTotal&&flag){
                    /**
                     * 当前数据处于的页数(从0开始)
                     * 例如item总数为10,更新数据条数为20,则10%20=0,则处于第10/20=0页
                     * 例如item总数为20,更新数据条数为20,则20%20=0,则处于第20/20=1页
                     * 例如item总数为100,更新数据条数为20,则100%20=0,则处于第100/20=5页
                     *
                     * 例如item总数为101,更新数据条数为20,则101%20=1,则处于第101/20+1=6页
                     */
                    int currentpage=itemTotal%number==0?itemTotal/number:itemTotal/number+1;
                    int nextpage=currentpage+1;     //即将翻开的下一页的数目
                    if (nextpage<=maxpage&&flag){   //判断下一页是否超过总的限制的页数并且是否刷新完成
                        flag=false;         //刷新标志设置为false,开始刷新
                        addData();             //添加刷新数据
                    }
                }

            }
        });
        /**
         * 上拉加载(因为数据加载需要时间,所以应在子线程中运行,但是显示数据需要在主线程中,即runOnUiThread)
         */
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                try {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(1000);//模拟通过网络获取数据
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    initData();
                                    adapter.notifyDataSetChanged();
                                    swipeRefreshLayout.setRefreshing(false);
                                }
                            });
                        }
                    }).start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 子线程上拉添加数据
     */
    private void addData() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<20;i++){
                    Integer r= Integer.valueOf((int) (Math.random()*100));
                    data.add(r);
                }
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        adapter.notifyDataSetChanged();
                        flag=true;
                    }
                });
            }
        }).start();
    }

    /**
     * 初始化第一次打开时的数据
     */
    private void initData() {
        data.clear();
        for (int i=0;i<40;i++){
            Integer r= Integer.valueOf(i);
            data.add(r);
        }
    }
}

MyAdapter的代码
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    List<Integer> data=new ArrayList<Integer>();
    static class MyViewHolder extends RecyclerView.ViewHolder{
        TextView textView;
        public MyViewHolder(View itemView) {
            super(itemView);
            this.textView=itemView.findViewById(R.id.item_text);
        }
    }

    public MyAdapter(List<Integer> data) {
        super();
        this.data=data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item,null);
        MyViewHolder myViewHolder=new MyViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Integer da=data.get(position);
        holder.textView.setText(da+"");
    }

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




到这里,我们的整个RecyclerView系列之(3)就实现了, 这三篇文章,它能做到的,ListView都可以做到,并没有体现出RecyclerView的灵活性,关于RecyclerView的灵活性, 很多人会想到一个词:瀑布流,看下图


图片来自于网络

而下一篇文章我会带来RecyclerView瀑布流的实现,谢谢咯。


最近挺忙,但是忙也不是不写文章的借口。

日记本

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!



作者:右眼皮的爱
链接:http://www.jianshu.com/p/3bf125b4917d
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值