开发者头条(五):实现recyclerview的上拉加载 + 下拉刷新
学习Ansen的博客,原文:带你实现开发者头条APP(五)–RecyclerView下拉刷新上拉加载 ,这一篇写的很详细。
知识点
今天主要是实现recyclerview的上拉加载跟多和下拉刷新,依赖的项目是CommonPullToRefresh,由于我们要加入轮播图,需要修改源码,所以依赖采用import module的形式。
最新的CommonPullToRefresh不需要修改源码,我们直接在build.gradle中引用即可
compile 'com.chanven.lib:cptr:1.1.0'
见图:
效果图:
布局中怎么引用?
直接在用PtrClassicFrameLayout包裹recyclerview,各属性github上介绍的很详细。
<com.chanven.lib.cptr.PtrClassicFrameLayoutandroid:id="@+id/ptrFlameLayout"xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#f0f0f0"cube_ptr:ptr_duration_to_close="200"cube_ptr:ptr_duration_to_close_header="1000"cube_ptr:ptr_keep_header_when_refresh="true"cube_ptr:ptr_pull_to_fresh="false"cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"cube_ptr:ptr_resistance="1.7"><android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"></android.support.v7.widget.RecyclerView>
</com.chanven.lib.cptr.PtrClassicFrameLayout>
使用步骤
- 对原adapter进行封装
- 将轮播图的view添加到新adapter
- 给recyclerview设置adapter
- 给PtrClassicFrameLayout设置下拉刷新监听
- 给PtrClassicFrameLayout设置上拉加载更多的监听
- 给PtrClassicFrameLayout设置可以加载更多
原adapter必须继承RecyclerView.Adapter<>,泛型必须是RecyclerView.ViewHolder,不能是:
MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.MyViewHolder>
adapter = new MyRecyclerAdapter(context, list);
mAdapter = new RecyclerAdapterWithHF((RecyclerView.Adapter)adapter);
mAdapter.addCarousel(initHeadView());
recyclerView.setAdapter(mAdapter);ptrFlameLayout.setPtrHandler(ptrDefaultHandler);
ptrFlameLayout.setOnLoadMoreListener(onLoadMoreListener);
ptrFlameLayout.setLoadMoreEnable(true);
怎么实现顶部加入轮播图 ?
Asen说 需要对RecyclerAdapterWithHF进行改造,我照着修改了,显示正常,修改的内容如下。
但我引用最新的,没做修改,也可以使用,不知道是不是作者修改了。添加轮播图直接调用方法:
mAdapter.addHeader(initHeadView());
- 定义一个集合保存轮播图的view,如果轮播图只有一个,可以用一个变量View
- 定义轮播图类型type(int)
- 在getViewtType(..)中返回轮播图类型
- 在onCreateViewHolder(..)中修改一点,就是在if判断中非HeadView + 非FootView + 非Carousel都要加入framelayout
- 在onBindViewHolder(..)绑定
- 对外提供一个方法:把轮播图增加到adapter
1 定义一个集合保存轮播图的view,如果轮播图只有一个,可以用一个变量View
private List<View> mHeaders = new ArrayList<View>();
private List<View> mFooters = new ArrayList<View>();
private List<View> mCarousel = new ArrayList<View>();//存放轮播图的集合
2 定义轮播图类型type(int)
public static final int TYPE_HEADER = 7898;
public static final int TYPE_FOOTER = 7899;
public static final int TYPE_CAROUSEL = 7900;//轮播图的viewtype
3 在getViewtType(..)中返回轮播图类型
增加的代码:
else if (isCarousel(position)) {//是则返回轮播图类型return TYPE_CAROUSEL;
}
增加后:
@Override
public final int getItemViewType(int position) {// check what type our position is, based on the assumption that the// order is headers > items > footersif (isHeader(position)) {return TYPE_HEADER;} else if (isCarousel(position)) {//是则返回轮播图类型return TYPE_CAROUSEL;} else if (isFooter(position)) {return TYPE_FOOTER;}int type = getItemViewTypeHF(getRealPosition(position));if (type == TYPE_HEADER || type == TYPE_FOOTER) {throw new IllegalArgumentException("Item type cannot equal " + TYPE_HEADER + " or " + TYPE_FOOTER);}return type;
}
其中isCarousel(position)是
//判断是不是轮播图isCarousel
private boolean isCarousel(int position) {return (mCarousel.size() > 0 && position == mHeaders.size());
}
作者判断是不是头尾的代码:
private boolean isHeader(int position) {return (position < mHeaders.size());
}private boolean isFooter(int position) {return (position >= mHeaders.size() + getItemCountHF());
}
4 在onCreateViewHolder(..)中修改一点,就是在if判断中非HeadView + 非FootView + 非Carousel都要加入framelayout
增加的代码:
type != TYPE_CAROUSEL
增加后:
@Override
public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {// if our position is one of our items (this comes from// getItemViewType(int position) below)if (type != TYPE_HEADER && type != TYPE_FOOTER && type != TYPE_CAROUSEL) {//不是轮播图类型ViewHolder vh = onCreateViewHolderHF(viewGroup, type);return vh;// else we have a header/footer} else {// create a new framelayout, or inflate from a resourceFrameLayout frameLayout = new FrameLayout(viewGroup.getContext());// make sure it fills the spaceframeLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));return new HeaderFooterViewHolder(frameLayout);}
}
5 在onBindViewHolder(..)绑定
增加的代码:
//headView是0,下一个的position是mHead.size()
else if (mCarousel.size() > 0 && position == mHeaders.size()) {//取出轮播图:View v = mCarousel.get(position);prepareHeaderFooter((HeaderFooterViewHolder) vh, v);
}
增加后:
@Override
public final void onBindViewHolder(final RecyclerView.ViewHolder vh, int position) {// check what type of view our position isif (isHeader(position)) {View v = mHeaders.get(position);// add our view to a header view and display itprepareHeaderFooter((HeaderFooterViewHolder) vh, v);} else if (mCarousel.size() > 0 && position == mHeaders.size()) {//headView是0,下一个的position是mHead.size()//取出轮播图:View v = mCarousel.get(position);prepareHeaderFooter((HeaderFooterViewHolder) vh, v);} else if (isFooter(position)) {View v = mFooters.get(position - getItemCountHF() - mHeaders.size());// add our view to a footer view and display itprepareHeaderFooter((HeaderFooterViewHolder) vh, v);} else {vh.itemView.setOnClickListener(new MyOnClickListener(vh));vh.itemView.setOnLongClickListener(new MyOnLongClickListener(vh));// it's one of our items, display as requiredonBindViewHolderHF(vh, getRealPosition(position));}
}
6 对外提供一个方法:把轮播图增加到adapter
//add a carousel to the adapter
public void addCarousel(View carousel) {mCarousel.add(carousel);
}
或者:
//add a carousel to the adapter
public void addCarousel(View carousel) {if(!mCarousel.contains(carousel)){mCarousel.add(carousel);notifyItemInserted(mHeaders.size());}
}
解决轮播图的BUG:
引用轮播图我们发现:无限次的自动循环正确,但是我们无法手滑,或者手滑卡顿,这是因为viewpager的滑动冲突
解决方法:
ptr.disableWhenHorizontalMove(true);//ptr与viewpager的滑动冲突
怎么实现下拉刷新?
ptrFlameLayout.setPtrHandler(ptrDefaultHandler);//下拉刷新
private PtrDefaultHandler ptrDefaultHandler = new PtrDefaultHandler() {@Overridepublic void onRefreshBegin(PtrFrameLayout frame) {initData();//初始化数据mAdapter.notifyDataSetChanged();//更新uiptrFlameLayout.refreshComplete();//刷新完成}
};
怎么实现上拉加载更多?
ptrFlameLayout.setOnLoadMoreListener(onLoadMoreListener);//上拉加载更多
private OnLoadMoreListener onLoadMoreListener = new OnLoadMoreListener() {@Overridepublic void loadMore() {mHandler.sendEmptyMessageDelayed(0,3000);}
};private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Frag1Bean bean = new Frag1Bean();bean.id = 100;bean.title = "新增数据";list.add(bean);mAdapter.notifyDataSetChanged();ptrFlameLayout.loadMoreComplete(true);}
};
对第4天的adapter的修改
由于day04我们实现了头部增加了轮播图的操作,现在要把它去掉,下文注释掉的就是需要去掉的
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// if (headView != null && viewType == TYPE_HEADVIEW) {// return new MyViewHolder(headView);
// }View view = LayoutInflater.from(context).inflate(R.layout.item_frag1, parent, false);return new MyViewHolder(view);
}@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {MyViewHolder holder = (MyViewHolder) viewHolder;
// if (getItemViewType(position) == TYPE_HEADVIEW){// return;
// }Frag1Bean bean = list.get(position);holder.tv_title.setText("" + bean.title);holder.tv_like.setText("" + bean.likeNumbers);holder.tv_comment.setText("" + bean.commentsNumbers);
}// @Override
// public int getItemViewType(int position) {// if (headView == null) {// return TYPE_NORMAL;
// }
// if (position == 0) {// return TYPE_HEADVIEW;
// }
// return TYPE_NORMAL;
// }public MyViewHolder(View itemView) {super(itemView);
// if (itemView == headView) {// return;
// }tv_title = (TextView) itemView.findViewById(R.id.tv_item_title);tv_like = (TextView) itemView.findViewById(R.id.tv_item_like);tv_comment = (TextView) itemView.findViewById(R.id.tv_item_comment);}
如何实现点击事件
方法 | 含义 |
---|---|
mAdapter.setOnItemClickListener(…) | 短点击 |
mAdapter.setOnItemLongClickListener(…) | 长点击 |
mAdapter | RecyclerAdapterWithHF 类型 |
RecyclerViewAdapter adapter = new RecyclerViewAdapter(list);
RecyclerAdapterWithHF mAdapter = new RecyclerAdapterWithHF(adapter);
//短点击
mAdapter.setOnItemClickListener(new RecyclerAdapterWithHF.OnItemClickListener() {@Overridepublic void onItemClick(RecyclerAdapterWithHF adapter, RecyclerView.ViewHolder vh, int position) {Log.d("tag","position="+position);}});//长点击
mAdapter.setOnItemLongClickListener(new RecyclerAdapterWithHF.OnItemLongClickListener() {@Overridepublic void onItemLongClick(RecyclerAdapterWithHF adapter, RecyclerView.ViewHolder vh, int position) {}});
解决滑动冲突
由于我把Toolbar放在了HomeFragment中,导致Frag1中的coordinateLayout不在一个布局中,所以无法我就在frag1中加了TextView来演示“滑动顶部固定”的效果,没出现滑动冲突,大家有冲突的话看作者的原博吧。
另外,我在android4.1.1上coordinateLayout没有效果,在android5.1有效果。
源码下载
https://git.oschina.net/DevelopHeadLine/DevelopHeadLine5
原博链接:
带你实现开发者头条(一) 启动页实现
带你实现开发者头条(二) 实现左滑菜单
带你实现开发者头条APP(三) 首页实现
带你实现开发者头条APP(四)—首页优化(加入design包)
带你实现开发者头条APP(五)–RecyclerView下拉刷新上拉加载
开发者头条(五):实现recyclerview的上拉加载 + 下拉刷新相关推荐
- php微信小程序向下滑动,微信小程序功能实现:上滑加载下拉刷新
本篇文章给大家带来的内容是关于微信小程序功能实现:上滑加载下拉刷新,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 之前谈到文章列表的数据加载,是一次性全部加载,这样是不友好的.这章介 ...
- 教你如何使用SwipeRefreshLayout来构建一个上拉加载下拉刷新框架
前言: 基本上所以的移动端应用都有Listview(当然RecyclerView也一样),那必不可少的都会嵌入一个上拉加载下拉刷新的功能.这样能大大的减少用户的流量消耗,同样对于用户也有更好的用户体验 ...
- ionic上拉加载-下拉刷新
ionic上拉加载-下拉刷新 1.上拉加载 <ion-infinite-scroll on-infinite="loadOlderStories()" distance=&q ...
- Mint-ui中loadmore(上拉加载下拉刷新)组件在ios中滑动会触发点击事件的解决方法...
bug说明: Mint-ui中loadmore(上拉加载下拉刷新)组件 在 使用fastclick的情况下 ,在ios设备中滑动会触发点击事件: 解决方法: 我是按需引入,去项目中找到loadmore ...
- php mescroll,mescroll.js上拉加载下拉刷新组件使用详解
本文实例为大家分享了上拉加载下拉刷新组件mescroll.js的具体代码,供大家参考,具体内容如下 使用注意事项: 1.引入的时候出问题及时看官方给出的解决方案(基本上都必须看): 2.react中一 ...
- ios 上拉加载 下拉刷新
在一款 App应用中有的时候会用到上拉加载下拉刷新的功能,本人觉得SVPullToRefresh很好用(可以用在UIScrollView上,包括UITableview和UICollectionView ...
- 微信小程序入门五上滑加载下拉刷新
之前谈到文章列表的数据加载,是一次性全部加载,这样是不友好的.这章介绍加载和刷新. 效果图: 先介绍在IDE中,怎么模拟上滑这个操作.开始我是用鼠标点击文章列表,然后先上移动.结果一直没有结果,以为是 ...
- Android 智能上拉加载下拉刷新框架之SmartRefreshLayout
1.说明: SmartRefreshLayout的目标是打造一个强大,稳定,成熟的下拉刷新框架,并集成各种的炫酷.多样.实用.美观的Header和Footer.它不只是支持所有的View,还支持多层嵌 ...
- 上拉加载下拉刷新了解下
2019独角兽企业重金招聘Python工程师标准>>> 老样子,我们先,哦不,今天我们直接上思路,没有效果图,真的没有 我们依旧从界面及逻辑两块进行分析 1.界面上,只分成简单的两块 ...
最新文章
- 基于生成式深度学习方法设计潜在2019-nCoV蛋白酶抑制剂
- 初识OR Mapping
- POJ-1724 深搜剪枝
- 走近虚拟机——McAfee研究员孙冰谈虚拟机技术和虚拟机安全
- 工程师如何在工作中提升自己?
- Java虚拟机(JVM)参数配置说明
- 联想linux笔记本评测,联想(lenovo)G460AL-ITH Linux笔记本电脑接口评测-ZOL中关村在线...
- 远程桌面连接服务器,提示身份验证错误,要求的函数不受支持,但又找不到加密Oracle修正
- CI框架 -- URL
- Spring IOC(控制反转)思想笔记
- 刚开完2019WWDC 苹果就被iOS开发者们集体起诉...
- [Toolkit]最新Silverlight Toolkit中的DragDrop支持
- c#之new关键词——隐藏基类方法
- 4412开发板团购活动
- JavaScript实现动态时间显示功能
- 一文搞懂机器学习准确率(Accuracy)、精确率(Pecision)、召回率(Recall)以及TP、FP、TN、FN
- OA会议 04 (查询会议签字)
- 高德地图点击不同的标记,动态传入参数创建信息窗体
- Android studio2.0在app中设置背景图片及添加图片资源
- MP地面站二次开发教程(四)地面站优化及其功能测试