RecyclerView下拉刷新与上拉加载 |
您所在的位置:网站首页 › 下拉可以刷新待取件 › RecyclerView下拉刷新与上拉加载 |
转载:【江清清的博客】 目录 SwipeRefrshLayoutRecyclerView+SwpieRefreshLayout实现下拉刷新效果布局文件onRefresh()RecyclerView.Adapter RecyclerView设置滚动事件加入上拉加载setOnScrollListener RecyclerView加入FootView实现上拉加载布局状态标志getItemCount()getItemViewTypeonCreateViewHolderonBindViewHolderRefreshFoot AdaptersetOnScrollListener SwipeRefreshLayout 、RecyclerView冲突下拉冲突的解决方案RecyclerView与ScrollView滑动冲突问题实现原理解决滑动冲突需要知道view传递 SwipeRefrshLayoutGoogle官方更新的一个Widget,可以实现下拉刷新的效果。 setOnRefreshListener(OnRefreshListener):添加下拉刷新监听器 setRefreshing(boolean):显示或者隐藏刷新进度条 isRefreshing():检查是否处于刷新状态 setColorSchemeResources():设置进度条的颜色主题,最多设置四种,以前的setColorScheme()方法已经弃用了。 RecyclerView+SwpieRefreshLayout实现下拉刷新效果 布局文件 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 newDatas = new ArrayList(); for (int i = 0; i private LayoutInflater mInflater; private List mTitles=null; public RefreshRecyclerAdapter(Context context){ this.mInflater=LayoutInflater.from(context); this.mTitles=new ArrayList(); for (int i=0;i 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 newDatas) { //mTitles.add(position, data); //notifyItemInserted(position); newDatas.addAll(mTitles); mTitles.removeAll(mTitles); mTitles.addAll(newDatas); notifyDataSetChanged(); } public void addMoreItem(List 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 newDatas = new ArrayList(); for (int i = 0; i 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{ //上拉加载更多 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 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(); for (int i=0;i //进行判断显示类型,来创建返回不同的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 newDatas) { //mTitles.add(position, data); //notifyItemInserted(position); newDatas.addAll(mTitles); mTitles.removeAll(mTitles); mTitles.addAll(newDatas); notifyDataSetChanged(); } public void addMoreItem(List 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(); } } setOnScrollListenerAdaper中我还定义一个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 newDatas = new ArrayList(); for (int i = 0; i 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() 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); } |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |