当前位置: 首页 > 科技观察

RecyclerView下拉刷新和上拉详解更多

时间:2023-03-14 00:58:29 科技观察

前言原文章中提到了如何使用RecyclerView添加页眉页脚。今天我们就深入展开,利用RecyclerView实现常见的下拉刷新和上拉加载。许多功能。当然,这些功能的实现也是建立在之前的RecyclerView中添加header和footer的基础上的。如果你不太了解,可以先看看之前的文章,或许能帮助你更好的理解。我已经上传到Jcenter中供大家使用,大家可以直接调用下面的代码获取:compile'com.idisfkj.enchancerecyclerview:mylibrary:1.1.1'EnhanceRecyclerView我将这个扩展的RecyclerView命名为EnhanceRecyclerView,继承RecyclerView。我们知道既然要实现下拉刷新和上拉多,就必须先实现头尾的布局,所以我们先利用前面的知识给EnhanceRecycleView添加header和footerpublicvoidinitView(){ViewheaderView=LayoutInflater.from(getContext()).inflate(R.layout.head_layout,null);ViewfooterView=LayoutInflater.from(getContext()).inflate(R.layout.footer_layout,null);addHeaderView(headerView);addFooterView(footerView);}布局文件就不多说了,至于addHeaderView和addFooterView方法,大家可以查看我之前的文章。设置监听器里面有详细的介绍。既然要实现下拉刷新和上拉加载,自然少不了监听器的处理,下面就来详细介绍一下。处理监听器OnScrollListener和OnTouchListener。OnScrollListener在EnhanceRecyclerView中添加addOnScrollListener来实现onScrollStateChanged和onScrolled方法。onScrolled在onScrolled中我们主要做的是获取EnhanceRcyclerView中item的总数,第一个item在EnhanceRecyclerView中视图显示的位置和最后一个item在EnhanceRecyclerView中视图显示中的位置。对于item的总数,直接调用totalCount=getLayoutManager().getItemCount()就很简单了;由于RecyclerView可以实现LinearLayoutManager、GridLayoutManager和StaggeredGridLayoutManager的不同布局,另外两个应该根据不同的manager来获取,下面看具体代码。if(getLayoutManager()instanceofLinearLayoutManager){lastItem=((LinearLayoutManager)getLayoutManager()).findLastVisibleItemPosition();firstVisible=((LinearLayoutManager)getLayoutManager()).findFirstVisibleItemPosition();}else{into=((StaggeredGridLayoutManager)getLayoutManager()).findLastVisibleItemPositions(into);firstInto=((StaggeredGridLayoutManager)getLayoutManager()).findFirstVisibleItemPositions(firstInto);lastItem=into[0];firstVisible=firstInto[0];}onScrollStateChanged得到三个关键数据后,实现具体逻辑在onScrollStateChanged。该方法中主要实现是处理更多的上拉加载if(lastItem==adapter.getItemCount()+1&&newState==RecyclerView.SCROLL_STATE_IDLE&&!isLoad){ViewGroup.LayoutParamsparams=getFooterView(0).getLayoutParams();params.width=RecyclerView.LayoutParams.MATCH_PARENT;params.height=RecyclerView.LayoutParams.WRAP_CONTENT;getFooterView(0).setLayoutParams(params);getFooterView(0).setVisibility(View.VISIBLE);smoothScrollToPosition(totalCount);isLoad=true;loadMoreListener.onLoadMore();}if(firstVisible==0){isTop=true;}else{isTop=false;RecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)getHeaderView(0).getLayoutParams();params.width=RecyclerView.LayoutParams.MATCH_PARENT;params.height=RecyclerView.LayoutParams.WRAP_CONTENT;params.setMargins(0,-getHeaderView(0).getHeight(),0,0);getHeaderView(0).setLayoutParams(params);}简单来说,核心就是判断lastItem是否在底部位置,如果是,继续加载更多的操作,这里提供了数据处理的接口,所以只需要实现loadMoreListener.onLoadMore();您可以拉起并加载更多内核。监听器主要处理下拉刷新。我们要分别处理我们熟悉的MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE和MotionEvent.ACTION_UP。ACTION_DOWN只是获取按下的坐标位置,这里就不多说了。下面主要关注另外两个。ACTION_MOVE的逻辑是处理触摸,根据滑动距离动态改变headertext和layoutview的显示。publicvoidtouchMove(MotionEventevent){endY=event.getY();moveY=endY-startY;//防止项目向上滑出if(moveY>0&&!isRefreshing){//防止返回文本显示异常scrollToPosition(0);if(getHeaderView(0).getVisibility()==GONE)getHeaderView(0).setVisibility(VISIBLE);RecyclerView.LayoutParamsparams=(RecyclerView.LayoutParams)getHeaderView(0).getLayoutParams();params.width=RecyclerView.LayoutParams.MATCH_PARENT;params.height=RecyclerView.LayoutParams.WRAP_CONTENT;//使header随moveY的值从顶部渐现if(moveY>=400){moveY=100+moveY/4;}else{moveY=moveY/2;}viewHeight=getHeaderView(0).getHeight();if(viewHeight<=0)viewHeight=130;moveY=moveY-viewHeight;params.setMargins(0,(int)moveY,0,0);getHeaderView(0).setLayoutParams(params);if(moveY>80){text.setText(getResources().getString(R.string.release_to_refresh));}else{text.setText(getResources().getString(R.string.pull_to_refresh));}}else{if(getHeaderView(0).getVisibility()!=GONE&&!isRefreshing){getHeaderView(0).setVisibility(GONE);}}}至于下拉时距顶部的距离变化,通过设置margin动态变化。看看代码。publicvoidtouchUp(){if(!isRefreshing&&(endY-startY)!=0){RecyclerView.LayoutParamsparams1=(RecyclerView.LayoutParams)getHeaderView(0).getLayoutParams();params1.width=RecyclerView.LayoutParams.MATCH_PARENT;params1.height=RecyclerView.LayoutParams.WRAP_CONTENT;if(moveY>=80){text.setText(getResources().getString(R.string.refreshing));params1.setMargins(0,0,0,0);isRefreshing=true;//刷新数据pullToRefresh.onRefreshing();}else{if(viewHeight<=0)viewHeight=130;params1.setMargins(0,-viewHeight,0,0);getHeaderView(0).setVisibility(GONE);}getHeaderView(0).setLayoutParams(params1);}}代码中重要的部分都指出了,相信都能看懂,这样下拉和上拉的逻辑就基本实现了。让我们看看界面设计。下拉和上拉接口(听众(ListenerLoadMoreifListener)pullToRefresh==null){initListener();}this.loadMoreListener=loadMoreListener;}在应用中添加接口监听时,初始化之前为EnhanceRecyclerView设置的监听状态重置设置。在调用下拉刷新或者上拉加载更多之后,我们构造一个通用的方法让它实现,重置状态,更新数据,方便统一调用。publicvoidsetLoadMoreComplete(){RecyclerView.LayoutParamsparams=(LayoutParams)getFooterView(0).getLayoutParams();params.width=0;params.height=0;getFooterView(0).setLayoutParams(params);getFooterView(0).setVisibility(视图.GONE);this.getAdapter().notifyDataSetChanged();isLoad=false;}publicvoidsetRefreshComplete(){RecyclerView.LayoutParamsparams1=(RecyclerView.LayoutParams)getHeaderView(0).getLayoutParams();params1.width=RecyclerView.LayoutParams.MATCH_PARENT;params1.height=RecyclerView.LayoutParams.WRAP_CONTENT;params1.setMargins(0,-getHeaderView(0).getHeight(),0,0);getHeaderView(0).setLayoutParams(params1);getHeaderView(0).setVisibility(GONE);this.getAdapter().notifyDataSetChanged();isRefreshing=false;}所用工作已经完成下面来做一个调整使用示范使用xml中引设置监听器mRecyclerView.setPullToRefreshListener(newcom.idisfkj.mylibrary.EnhanceRecyclerView.PullToRefreshListener(){@OverridepublicvoidonRefreshing(){refreshData();}});mRecyclerView.setLoadMoreListener(newEnhanceRecyclerView.LoadMoreListenerepload(){@OrehanceRecyclerView.LoadMoreListenerepload(){大声的);}});refreshingData()和loadMoreData()加载数据的逻辑就不展示了,只需要记得在请求网络数据后调用里面对应的mRecyclerView.setRefreshComplete()和mRecyclerView.setLoadMoreComplete()来重置状态至于其他的设置Adapter、LayoutManager等,我就不多说了,和原来的RecyclerView是一样的。总结其实一般来说,添加页眉和页脚有两个难点。这个之前已经攻克过了,原理比较简单,实现触摸和滑动监听逻辑。这里主要是对逻辑的理解,对整个刷新过程进行整体分析,可以很好的理解上面的代码。这些项目只要对视图的动态显示做相应的改动,调用接口就可以很好的处理。当然,上面的实现可能还是有缺陷的。希望指出,我会做相应的修改,也可以修改后提交给我。我会统一修改,谢谢!