学习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的上拉加载 + 下拉刷新相关推荐

  1. php微信小程序向下滑动,微信小程序功能实现:上滑加载下拉刷新

    本篇文章给大家带来的内容是关于微信小程序功能实现:上滑加载下拉刷新,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 之前谈到文章列表的数据加载,是一次性全部加载,这样是不友好的.这章介 ...

  2. 教你如何使用SwipeRefreshLayout来构建一个上拉加载下拉刷新框架

    前言: 基本上所以的移动端应用都有Listview(当然RecyclerView也一样),那必不可少的都会嵌入一个上拉加载下拉刷新的功能.这样能大大的减少用户的流量消耗,同样对于用户也有更好的用户体验 ...

  3. ionic上拉加载-下拉刷新

    ionic上拉加载-下拉刷新 1.上拉加载 <ion-infinite-scroll on-infinite="loadOlderStories()" distance=&q ...

  4. Mint-ui中loadmore(上拉加载下拉刷新)组件在ios中滑动会触发点击事件的解决方法...

    bug说明: Mint-ui中loadmore(上拉加载下拉刷新)组件 在 使用fastclick的情况下 ,在ios设备中滑动会触发点击事件: 解决方法: 我是按需引入,去项目中找到loadmore ...

  5. php mescroll,mescroll.js上拉加载下拉刷新组件使用详解

    本文实例为大家分享了上拉加载下拉刷新组件mescroll.js的具体代码,供大家参考,具体内容如下 使用注意事项: 1.引入的时候出问题及时看官方给出的解决方案(基本上都必须看): 2.react中一 ...

  6. ios 上拉加载 下拉刷新

    在一款 App应用中有的时候会用到上拉加载下拉刷新的功能,本人觉得SVPullToRefresh很好用(可以用在UIScrollView上,包括UITableview和UICollectionView ...

  7. 微信小程序入门五上滑加载下拉刷新

    之前谈到文章列表的数据加载,是一次性全部加载,这样是不友好的.这章介绍加载和刷新. 效果图: 先介绍在IDE中,怎么模拟上滑这个操作.开始我是用鼠标点击文章列表,然后先上移动.结果一直没有结果,以为是 ...

  8. Android 智能上拉加载下拉刷新框架之SmartRefreshLayout

    1.说明: SmartRefreshLayout的目标是打造一个强大,稳定,成熟的下拉刷新框架,并集成各种的炫酷.多样.实用.美观的Header和Footer.它不只是支持所有的View,还支持多层嵌 ...

  9. 上拉加载下拉刷新了解下

    2019独角兽企业重金招聘Python工程师标准>>> 老样子,我们先,哦不,今天我们直接上思路,没有效果图,真的没有 我们依旧从界面及逻辑两块进行分析 1.界面上,只分成简单的两块 ...

最新文章

  1. 基于生成式深度学习方法设计潜在2019-nCoV蛋白酶抑制剂
  2. 初识OR Mapping
  3. POJ-1724 深搜剪枝
  4. 走近虚拟机——McAfee研究员孙冰谈虚拟机技术和虚拟机安全
  5. 工程师如何在工作中提升自己?
  6. Java虚拟机(JVM)参数配置说明
  7. 联想linux笔记本评测,联想(lenovo)G460AL-ITH Linux笔记本电脑接口评测-ZOL中关村在线...
  8. 远程桌面连接服务器,提示身份验证错误,要求的函数不受支持,但又找不到加密Oracle修正
  9. CI框架 -- URL
  10. Spring IOC(控制反转)思想笔记
  11. 刚开完2019WWDC 苹果就被iOS开发者们集体起诉...
  12. [Toolkit]最新Silverlight Toolkit中的DragDrop支持
  13. c#之new关键词——隐藏基类方法
  14. 4412开发板团购活动
  15. JavaScript实现动态时间显示功能
  16. 一文搞懂机器学习准确率(Accuracy)、精确率(Pecision)、召回率(Recall)以及TP、FP、TN、FN
  17. OA会议 04 (查询会议签字)
  18. 高德地图点击不同的标记,动态传入参数创建信息窗体
  19. Android studio2.0在app中设置背景图片及添加图片资源
  20. MP地面站二次开发教程(四)地面站优化及其功能测试

热门文章

  1. WPF 子窗打开时在父窗显示蒙板
  2. Gyp语法规则参考 工具的使用
  3. 微信小程序 wx.showToast() 更换icon图标
  4. 用matlab计算超调,怎样用matlab计算超调量、峰值时间
  5. C++ (MFC) 编写注册表,使开机自启动
  6. 读书百客:《寒塘》赏析
  7. 10个数冒泡排序法c语言代码,输入10个数用冒泡法排序
  8. Windows上安装Linux子系统
  9. java7 arm_为Android ARM7编译Mono
  10. 广西2022农民丰收节 国稻种芯:自治区主场平南富硒石硖龙眼节