查看原文
其他

手把手教你实现RecyclerView实现上拉刷新功能

2017-08-31 刘畅 终端研发部


前言介绍

使用RecyclerView实现底部上拉刷新

项目地址:

http://xiaoniaojun.cn/2017/05/08/使用RecyclerView实现底部上拉刷新.html

正文

首先来看一下效果吧:

  onCreateViewHolder  

首先来看一下Adapter中的onCreateViewHolder方法:

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);

我们重点关注viewType这个参数。在onCreateViewHolder回调时,系统会传入这个viewType,表示列表中每个项的View的类型。

这个viewType是个整形值,默认为0。我们可以通过在Adapter内重写public int getItemViewType(int position)方法来设置viewType。

这就是在RecyclerView中实现多类型View的关键。

  如何实现上拉刷新  

首先我们要考虑上拉刷新的过程:

在用户将RecyclerView拉到底部的时候,出现“正在刷新内容”的提示。此时,开始请求新内容并添加至Adapter中的数据容器列表中。

所以,这个过程里有如下几个关键点:

  • 1.如何在列表底部现实“正在刷新内容”的提示View;

  • 2.如何在到达列表底部的时候获得通知(回调);

  • 3.如何动态地向RecyclerView中添加新的数据项目。

下面我们就来依次解决每一个关键点。

  在列表底部现实“正在刷新内容”的提示View  

可以这样实现,在底部永远都加入一个显示提示的LoadingMoreView:

为此,我们需要在Adapter中修改几个地方:

在getItemCount()方法中+1,因为添加了一个LoadingMoreView

@Overridepublic int getItemCount() {        // 在列表底部添加了一个 View:Lading more    return mItems.size() + 1; }

然后,为普通的Item View和LoadingMoreView设置viewType:

private static final int VIEW_TYPE_NORMAL = 1;
private static final int VIEW_TYPE_LOADING_MORE = 2; // 复写此方法以确定viewType    @Override    
   public int getItemViewType(int position) {        
               int type = VIEW_TYPE_NORMAL;        // 如果当前position是列表底部,则为LoadingMoreView        
               if (position == mItems.size())            
               type = VIEW_TYPE_LOADING_MORE;        
               return type;    }

然后,还需要为这个LoadingMoreView编写ViewHodler。由于不需要修改其内容,所以写一个最简单的ViewHolder就可以了:

123456public class LoadingMoreVH extends RecyclerView.ViewHolder {        public LoadingMoreVH(View itemView) {            
           super(itemView);        }    }

之后,修改onCreateViewHolder和onBindViewHolder,主要是判断何时该处理不同的View,这里给出示例,大家自己体会一下:

   @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        
           if (viewType == VIEW_TYPE_NORMAL) {            View view = mInflater.inflate(R.layout.item_zhihu_home_first, parent, false);            
           final VH holder = new VH(view);            holder.itemView.setOnClickListener(new View.OnClickListener() {                
               @Override                public void onClick(View v) {                    
                   int position = holder.getAdapterPosition();                    
                       if (mClickListener != null) {                        mClickListener.onItemClick(position, v, holder);                    }                }            });            
           return holder;            // 处理LoadingMoreView        } else {            View view = mInflater.inflate(R.layout.item_load_more, parent, false);            
           return new LoadingMoreVH(view);        }    }    
   @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {    // 避开LoadingMoreV        if (position < mItems.size()) {            Article item = mItems.get(position);            ((VH) holder).img.setImageResource(item.getImgRes());            ((VH) holder).tvTitle.setText(item.getTitle());        }    }

  在到达列表底部的时候获得回调 及 动态地添加新的数据项目  

RecyclerView并没有为我们提供类似的回调,所以我们需要手动实现它。 这里我们利用OnScrollListener()来实现。

// 在Activity中
   private boolean loading = true;
   int pastVisibleItems, visibleItemCount, totalItemCount;    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            
           @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                
               super.onScrolled(recyclerView, dx, dy);                mScrollTotal += dy;                                if (dy > 0) {                    visibleItemCount = mLayoutmanager.getChildCount();                    totalItemCount = mLayoutmanager.getItemCount();                    pastVisibleItems = mLayoutmanager.findFirstVisibleItemPosition();                    
                       if (loading) {                        
                           if (visibleItemCount + pastVisibleItems >= totalItemCount) {                            // 滚动到列表底部                            loading = false;                            // 产生回调                            onScrollReachedBottom();                        }                    }                }            }        });

在onScrolled()回调中,我们通过findFirstVisibleItemPosition和getChildCount()可以算出当前屏幕中,最底部项目的索引号。只需要将它与Adapter中的数据列表元素总数一比较,就可以得出是否滚动到了RecyclerView底部。

我们再写一个接口作为回调:

interface OnScrollReachedBottomListener {    
   void onScrollReachedBottom(); }

然后在当前Activity中实现这个接口就可以得到回调了。 下面是我的demo中的回调方法,在其中执行请求(网络)新数据,并通过:

// RecyclerView滚动到最后一个元素    @Override    
   public void onScrollReachedBottom()
{        Log.v(TAG,"到达列表最后一个元素。");        // 模拟请求延迟        Handler handler = new Handler();        handler.postDelayed(new Runnable() {            @Override            
           public void run()
{                // 产生mock数据                ArrayList<Article> list = new ArrayList<>();                
                   for (int i = 0; i < 2; i++) {                    
                   int index = i % 2;                    Article article = new Article(mTitles[index+5], mImgRes[index]);                    
                   list.add(article);                }                
               // 注意这个 -1,不要将数据插入到“正在载入”提示View之后去了                int insertPosition = mAdapter.getItemCount() - 1;                mAdapter.addDatas(list);                
               // 使用该方法更新数据,可以保持当前用户的滚动位置                mAdapter.notifyItemInserted(insertPosition);                                loading = true;            }        },300);    }

为了要在Adapter中插入新数据,需要在Adapter中添加一个addDatas()方法:

public void addDatas(List<Article> items) {        mItems.addAll(items);  
 }


博客地址:

http://xiaoniaojun.cn/2017/05/08/使用RecyclerView实现底部上拉刷新.html

终端研发部提倡 没有做不到的,只有想不到的

在这里获得的不仅仅是技术!


让心,在阳光下学会舞蹈

让灵魂,在痛苦中学会微笑

—终端研发部—



如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809   

微信公众号:终端研发部


            

这里学到不仅仅是技术

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存