RecyclerView下拉刷新与上拉加载

转载:【江清清的博客】

SwipeRefrshLayout

Google官方更新的一个Widget,可以实现下拉刷新的效果。

setOnRefreshListener(OnRefreshListener):添加下拉刷新监听器
setRefreshing(boolean):显示或者隐藏刷新进度条
isRefreshing():检查是否处于刷新状态
setColorSchemeResources():设置进度条的颜色主题,最多设置四种,以前的setColorScheme()方法已经弃用了。

RecyclerView+SwpieRefreshLayout实现下拉刷新效果

布局文件

<?xmlversion="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"android:layout_width="match_parent"
   android:layout_height="match_parent">
    <includelayout="@layout/common_top_bar_layout"/>
   <android.support.v4.widget.SwipeRefreshLayout
       android:id="@+id/demo_swiperefreshlayout"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
        android:scrollbars="vertical"
        >
       <android.support.v7.widget.RecyclerView
           android:id="@+id/demo_recycler"
           android:layout_width="fill_parent"
           android:layout_height="fill_parent"
           ></android.support.v7.widget.RecyclerView>
   </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>

onRefresh()

在Activity中获取SwipeRefreshLayout控件并且设置OnRefreshListener监听器,同时实现里边的onRefresh()方法,在该方法中进行网络请求最新数据,然后刷新RecyclerView列表同时设置SwipeRefreshLayout的进度Bar的隐藏或者显示效果。

demo_swiperefreshlayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                Log.d("zttjiangqq","invoke onRefresh...");
                new Handler().postDelayed(newRunnable() {
                    @Override
                    public void run() {
                        List<String> newDatas = new ArrayList<String>();
                        for (int i = 0; i <5; i++) {
                            int index = i + 1;
                           newDatas.add("new item" + index);
                        }
                       adapter.addItem(newDatas);
                       demo_swiperefreshlayout.setRefreshing(false);
                       Toast.makeText(RecyclerRefreshActivity.this, "更新了五条数据...", Toast.LENGTH_SHORT).show();
                    }
                }, 5000);
            }
        });

RecyclerView.Adapter

public class RefreshRecyclerAdapter extends RecyclerView.Adapter<RefreshRecyclerAdapter.ViewHolder>{
    private LayoutInflater mInflater;
    private List<String> mTitles=null;
    public RefreshRecyclerAdapter(Context context){
       this.mInflater=LayoutInflater.from(context);
        this.mTitles=new ArrayList<String>();
        for (int i=0;i<20;i++){
            int index=i+1;
           mTitles.add("item"+index);
        }
    }
    /**
     * item显示类型
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final Viewview=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
        //这边可以做一些属性设置,甚至事件监听绑定
        //view.setBackgroundColor(Color.RED);
        ViewHolder viewHolder=new ViewHolder(view);
 
        return viewHolder;
    }
 
    /**
     * 数据的绑定显示
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
       holder.item_tv.setText(mTitles.get(position));
        holder.itemView.setTag(position);
    }
    @Override
    public int getItemCount() {
        return mTitles.size();
    }
 
    //自定义的ViewHolder,持有每个Item的的所有界面元素
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView item_tv;
        public ViewHolder(View view){
            super(view);
            item_tv = (TextView)view.findViewById(R.id.item_tv);
        }
    }
 
    //添加数据
    public void addItem(List<String> newDatas) {
        //mTitles.add(position, data);
        //notifyItemInserted(position);
        newDatas.addAll(mTitles);
        mTitles.removeAll(mTitles);
        mTitles.addAll(newDatas);
        notifyDataSetChanged();
    }
 
    public void addMoreItem(List<String> newDatas) {
        mTitles.addAll(newDatas);
        notifyDataSetChanged();
    }
}

RecyclerView设置滚动事件加入上拉加载

LayoutManger给我们提供了以下几个方法来让开发者方便的获取到屏幕上面的顶部item和顶部item相关的信息:
findFirstVisibleItemPosition()
findFirstCompletlyVisibleItemPosition()
findLastVisibleItemPosition()
findLastCompletlyVisibleItemPosition()

setOnScrollListener

通过监听滑动(滚动)事件,然后在里边判断是否已经滑动到最底部来加载更多的数据

 //RecyclerView滑动监听
        demo_recycler.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
               super.onScrollStateChanged(recyclerView, newState);
                if (newState ==RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 ==adapter.getItemCount()) {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            List<String> newDatas = new ArrayList<String>();
                            for (int i = 0; i< 5; i++) {
                                int index = i +1;
                               newDatas.add("more item" + index);
                            }
                           adapter.addMoreItem(newDatas);
                        }
                    },1000);
                }
            }
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView,dx, dy);
                lastVisibleItem =linearLayoutManager.findLastVisibleItemPosition();
            }
        });

RecyclerView加入FootView实现上拉加载

让用户知道确实在上拉加载的过程吧,例如加载一个底部的进度布局。这样一想,那么我们就按照ListView方式addFootView()呗,不过很可惜的是RecyclerView没有给我们提供addFootView(),有一个getItemViewType()返回是普通item还是底部刷新item

布局状态标志

加入布局状态标志-用来判断此时加载是普通Item还是foot view:

   private static final int TYPE_ITEM =0;  // 普通Item View
   private static final intTYPE_FOOTER = 1;  // 底部FootView

getItemCount()

重写getItemCount()方法,返回的Item数量在数据的基础上面+1,增加一项FootView布局项

   public int getItemCount() {
        return mTitles.size()+1;
    }

getItemViewType

  public int getItemViewType(int position) {
    // 最后一个item设置为footerView
    if (position + 1 == getItemCount()) {
                return TYPE_FOOTER;
            } else {
                return TYPE_ITEM;
            }
        }

onCreateViewHolder

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //进行判断显示类型,来创建返回不同的View
        if(viewType==TYPE_ITEM){
            Viewview=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
            //这边可以做一些属性设置,甚至事件监听绑定
           //view.setBackgroundColor(Color.RED);
            ItemViewHolder itemViewHolder=new ItemViewHolder(view);
            return itemViewHolder;
        }else if(viewType==TYPE_FOOTER){
            Viewfoot_view=mInflater.inflate(R.layout.recycler_load_more_layout,parent,false);
            //这边可以做一些属性设置,甚至事件监听绑定
           //view.setBackgroundColor(Color.RED);
            FootViewHolder footViewHolder=new FootViewHolder(foot_view);
            return footViewHolder;
        }
       return null;
    }

onBindViewHolder

 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof ItemViewHolder) {
           ((ItemViewHolder)holder).item_tv.setText(mTitles.get(position));
            holder.itemView.setTag(position);
        }else if(holder instanceof FootViewHolder){
            FootViewHolderfootViewHolder=(FootViewHolder)holder;
            switch (load_more_status){
                case PULLUP_LOAD_MORE:
                   footViewHolder.foot_view_item_tv.setText("上拉加载更多...");
                    break;
                case LOADING_MORE:
                   footViewHolder.foot_view_item_tv.setText("正在加载更多数据...");
                    break;
            }
        }
    }

RefreshFoot Adapter

packagecom.chinaztt.fda.adapter;
public class RefreshFootAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    //上拉加载更多
    public static final int  PULLUP_LOAD_MORE=0;
    //正在加载中
    public static final int  LOADING_MORE=1;
    //上拉加载更多状态-默认为0
    private int load_more_status=0;
    private LayoutInflater mInflater;
    private List<String> mTitles=null;
    private static final intTYPE_ITEM = 0;  //普通Item View
    private static final intTYPE_FOOTER = 1;  //顶部FootView
    public RefreshFootAdapter(Context context){
       this.mInflater=LayoutInflater.from(context);
        this.mTitles=new ArrayList<String>();
        for (int i=0;i<20;i++){
            int index=i+1;
           mTitles.add("item"+index);
        }
    }
    /**
     * item显示类型
     * @param parent
     * @param viewType
     * @return
     */
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //进行判断显示类型,来创建返回不同的View
        if(viewType==TYPE_ITEM){
            Viewview=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
            //这边可以做一些属性设置,甚至事件监听绑定
           //view.setBackgroundColor(Color.RED);
            ItemViewHolder itemViewHolder=new ItemViewHolder(view);
            return itemViewHolder;
        }else if(viewType==TYPE_FOOTER){
            Viewfoot_view=mInflater.inflate(R.layout.recycler_load_more_layout,parent,false);
            //这边可以做一些属性设置,甚至事件监听绑定
           //view.setBackgroundColor(Color.RED);
            FootViewHolder footViewHolder=new FootViewHolder(foot_view);
            return footViewHolder;
        }
       return null;
    }
 
    /**
     * 数据的绑定显示
     * @param holder
     * @param position
     */
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof ItemViewHolder) {
           ((ItemViewHolder)holder).item_tv.setText(mTitles.get(position));
            holder.itemView.setTag(position);
        }else if(holder instanceof FootViewHolder){
            FootViewHolder footViewHolder=(FootViewHolder)holder;
            switch (load_more_status){
                case PULLUP_LOAD_MORE:
                   footViewHolder.foot_view_item_tv.setText("上拉加载更多...");
                    break;
                case LOADING_MORE:
                   footViewHolder.foot_view_item_tv.setText("正在加载更多数据...");
                    break;
            }
        }
    }
 
    /**
     * 进行判断是普通Item视图还是FootView视图
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
    // 最后一个item设置为footerView
    if (position + 1 == getItemCount()) {
                return TYPE_FOOTER;
            } else {
                return TYPE_ITEM;
            }
        }
    @Override
    public int getItemCount() {
        return mTitles.size()+1;
    }
    //自定义的ViewHolder,持有每个Item的的所有界面元素
    public static class ItemViewHolder extends RecyclerView.ViewHolder {
        public TextView item_tv;
        public ItemViewHolder(View view){
            super(view);
            item_tv = (TextView)view.findViewById(R.id.item_tv);
        }
    }
    /**
     * 底部FootView布局
     */
    public static class FootViewHolder extends  RecyclerView.ViewHolder{
        private TextView foot_view_item_tv;
        public FootViewHolder(View view) {
            super(view);
           foot_view_item_tv=(TextView)view.findViewById(R.id.foot_view_item_tv);
        }
    }
 
    //添加数据
    public void addItem(List<String> newDatas) {
        //mTitles.add(position, data);
        //notifyItemInserted(position);
        newDatas.addAll(mTitles);
        mTitles.removeAll(mTitles);
        mTitles.addAll(newDatas);
        notifyDataSetChanged();
    }
 
    public void addMoreItem(List<String> newDatas) {
        mTitles.addAll(newDatas);
        notifyDataSetChanged();
    }
 
    /**
     * //上拉加载更多
     * PULLUP_LOAD_MORE=0;
     * //正在加载中
     * LOADING_MORE=1;
     * //加载完成已经没有更多数据了
     * NO_MORE_DATA=2;
     * @param status
     */
    public void changeMoreStatus(int status){
        load_more_status=status;
        notifyDataSetChanged();
    }
}

setOnScrollListener

Adaper中我还定义一个changeMoreStatus()方法和两个字符串常量可以来进行修改FootView中字符串提醒文本的。
整体Activity中还是设置监听RecyclerView的滚动事件.

demo_recycler.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
               super.onScrollStateChanged(recyclerView, newState);
                if (newState ==RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 ==adapter.getItemCount()) {
                   adapter.changeMoreStatus(RefreshFootAdapter.LOADING_MORE);
                    newHandler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            List<String> newDatas = new ArrayList<String>();
                            for (int i = 0; i< 5; i++) {
                                int index = i +1;
                               newDatas.add("more item" + index);
                            }
                           adapter.addMoreItem(newDatas);
                           adapter.changeMoreStatus(RefreshFootAdapter.PULLUP_LOAD_MORE);
                        }
                    }, 2500);
                }
            }
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView,dx, dy);
                lastVisibleItem =linearLayoutManager.findLastVisibleItemPosition();
            }
        });

SwipeRefreshLayout 、RecyclerView冲突下拉冲突的解决方案

出现RecyclerView没有滑动到顶部,手指向下滑动时,触发了SwipeRefreshLayout的刷新事件,造成了冲突。

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener(){
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            int topRowVerticalPosition =
                    (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
            swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
 
        }
 
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }
    });

RecyclerView与ScrollView滑动冲突问题

参考文章:
【Android 手势冲突】Colin带你彻底解决RecyclerView与ScrollView滑动冲突问题,并实现RecyclerView悬停导航栏(附demo哦)

实现原理

在进到页面中默认把滑动事件交给ScrollView,同时屏蔽RecyclerView的滑动事件;在RecyclerView滑动到顶部的时候,把滑动事件交给RecyclerView。
判断RecyclerView是否滑动到了屏幕顶部了呢?通过recyclerview的getTop方法得到recyclerview距离顶部的距离,然后通过scrollView的getScrollY方法得到ScrollView滑动的距离,只需要比较这两个值。

解决滑动冲突需要知道view传递

如何把事件传给内部View?
只需要在ScrollView滑动到某个位置后 getScrollY() >= recyclerView.getChildAt(0).getTop();
使用接口回调,并且让RecyclerView在接口回调里,getParent().requestdisallowintercept()。

RecyclerView如何把事件传给外部?
需要给RecyclerView设置ontouchlistener,然后在RecyclerView滑动到第一个item recyclerView.getChildAt(0).getTop()<=0;
并且正在向下滑动时,requestdisallowintercept(false)来让ScrollView拦截。

外部拦截法

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
 
        switch(ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //必须返回false,否则子控件永远无法拿到焦点
                return false;
            case MotionEvent.ACTION_MOVE:
                if(事件交给子控件的条件) {
                    return false;
                } else {
                    return super.onInterceptTouchEvent(ev);
                }
            case MotionEvent.ACTION_UP:
                //必须返回false,否则子控件永远无法拿到焦点
                return false;
            default:
                return super.onInterceptTouchEvent(ev);
         }
 
    }

内部拦截法

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch(ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //父容器禁止拦截
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                if(事件交给父容器的条件) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的示例代码: 首先,在XML布局文件中添加一个RecyclerView和SwipeRefreshLayout控件: ```xml <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> ``` 然后,在Activity或Fragment中初始化RecyclerView和SwipeRefreshLayout,并设置相应的监听器: ```java // 初始化RecyclerView和SwipeRefreshLayout mRecyclerView = findViewById(R.id.recycler_view); mSwipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); // 设置布局管理器和适配器 mLayoutManager = new LinearLayoutManager(this); mAdapter = new MyAdapter(mDataList); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setAdapter(mAdapter); // 设置下拉刷新监听器 mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { // 进行下拉刷新操作 refreshData(); } }); // 设置上加载更多监听器 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE && isSlideToBottom(recyclerView)) { // 滑动到底部,触发加载更多操作 loadMoreData(); } } }); // 判断RecyclerView是否滑动到底部 private boolean isSlideToBottom(RecyclerView recyclerView) { LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); int itemCount = layoutManager.getItemCount(); return lastVisibleItemPosition == (itemCount - 1); } // 进行下拉刷新操作 private void refreshData() { // 在这里进行刷新数据的操作 // 刷新完成后调用mSwipeRefreshLayout.setRefreshing(false)停止刷新动画 } // 进行上加载更多操作 private void loadMoreData() { // 在这里进行加载更多数据的操作 // 加载完成后调用mAdapter.notifyDataSetChanged()更新列表 } ``` 需要注意的是,上述代码中的MyAdapter是自定义的RecyclerView适配器,需要根据实际情况进行修改。另外,刷新和加载更多操作需要在子线程中进行,可以使用AsyncTask等方式进行异步处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值