Android实现RecyclerView的下拉刷新和上拉载入很多其它
需求
先上效果图, Material Design风格的下拉刷新和上拉载入很多其它。
源代码地址(欢迎star) https://github.com/studychen/SeeNewsV2
假设对于RecyclerView还不熟悉,參见这篇 Android Material Design学习之RecyclerView取代 ListView
本文链接 http://blog.csdn.net/never_cxb/article/details/50759109 转载请注明出处
下拉刷新
效果图
上拉时候会有一个圆形动画。刷新载入数据。
思路
使用Google官方的android.support.v4.widget.SwipeRefreshLayout
列表RecyclerView的xml布局
给原来的RecyclerView添加一个SwipeRefreshLayout的父布局
<?xml version="1.0" encoding="utf-8"?
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?
attr/listBackground"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 新闻列表展示-->
<android.support.v7.widget.RecyclerView
android:id="@+id/rcv_article_origin"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
java代码
这儿有几个注意点:
setColorSchemeColors()
能够控制圆形动画的颜色,最多设置4个。
setOnRefreshListener
设置下拉刷新的回调事件。
下拉刷新后。使用 AsyncTask 依据当前RecyclerView中首个Item的id来载入很多其它数据。
数据载入完成后,使用setRefreshing(false);
取消动画。
假设刷新后得到0条记录,提示没有数据更新
。若得到>0条数据。把数据加到RecyclerView中
mSwipeRefreshLayout.setColorSchemeColors(Color.RED, Color.BLUE);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new MoreArticleTask().execute(mAdapter.getTopArticleId());
}
});
// Integer 是输入參数
// 得到比某个id大的新闻数组
class MoreArticleTask extends AsyncTask<Integer, Void, List<SimpleArticleItem>> {
@Override
protected List<SimpleArticleItem> doInBackground(Integer... params) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return getMoreById(mColumn, params[0]);
}
@Override
protected void onPostExecute(List<SimpleArticleItem> simpleArticleItems) {
super.onPostExecute(simpleArticleItems);
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(false);
}
//没有新的数据。提示消息
if (simpleArticleItems == null || simpleArticleItems.size() == 0) {
Snackbar.with(mActivity.getApplicationContext()) // context
.text(mActivity.getResources().getString(R.string.list_more_data)) // text to display
.duration(Snackbar.SnackbarDuration.LENGTH_SHORT) // make it shorter
.show(mActivity); // activity where it is displayed
} else {
mArticleList.addAll(simpleArticleItems);
mAdapter.notifyDataSetChanged();
}
}
}
首次进入页面就显示载入ing的动画
效果例如以下:
直接使用 mSwipeRefreshLayout.setRefreshing(true);
载入动画初始状态并不显示。
看了 http://stackoverflow.com/questions/26858692/swiperefreshlayout-setrefreshing-not-showing-indicator-initially 的解答。
改用以下的代码,初始状态就有载入动画显示。
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
new MoreArticleTask().execute(mAdapter.getTopArticleId());
}
});
上拉载入很多其它
RecyclerView 展示列表是个通用需求。那么当数据较多时候。怎样实现分页载入呢?
比方笔者的项目中,先载入15条新闻,当滑动究竟部时候,再载入15条。
效果图
思路
在RecyclerView底部添加一个Footer的ViewHolder。数据载入完成取出底部的ViewHolder。
底部Footer的xml布局文件
非常easy,就是一个ProgressBar。本项目为了Material Design。使用了一个开源ProgressBar https://github.com/Todd-Davies/ProgressWheel,你也能够使用原生的ProgressBar。
<?
xml version="1.0" encoding="utf-8"?><!--上拉载入很多其它 RecyclerView 底部-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:wheel="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/rcv_load_more"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
wheel:matProg_barColor="@color/accent"
wheel:matProg_progressIndeterminate="true" />
</LinearLayout>
底部Footer的ViewHolder
/**
* 底部载入很多其它
*/
class FooterViewHolder extends RecyclerView.ViewHolder {
@InjectView(R.id.rcv_load_more)
ProgressWheel rcvLoadMore;
public FooterViewHolder(View itemView) {
super(itemView);
ButterKnife.inject(this, itemView);
}
}
在Fragment中给RecyclerView添加滑动监听
layoutManager.getItemCount()
能够得到当前RecyclerView中Item的总数目
layoutManager.findLastVisibleItemPosition()
得到最后一个可见的Item的位置position
假设 totalItemCount < (lastVisibleItem + Constant.VISIBLE_THRESHOLD)
比方一共15个Item,当前到达第13个, Constant.VISIBLE_THRESHOLD设为3
总数小于最后一个+阈值,就载入很多其它新闻数据。同一时候把loading标记为 true 。
private boolean loading = false;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
mAdapter = new OriginArticleAdapter(mActivity, mArticleList);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int totalItemCount = layoutManager.getItemCount();
int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount < (lastVisibleItem + Constant.VISIBLE_THRESHOLD)) {
new ArticleTask(mActivity).execute(mAdapter.getBottomArticleId());
loading = true;
}
}
});
}
在Fragment中控制底部Footer
我们依旧使用AsyncTask。
注意 onPreExecute()
给 mArticleList 添加了一个null标记Footer。假设是第一次进入页面(mArticleList为空)不须要加Footer。
当数据载入完成后。用 mArticleList.remove(mArticleList.size() - 1);
把最以下的Footer删除。
再用 mArticleList.addAll(moreArticles);
添加新增的新闻数据。
并用 mAdapter.notifyDataSetChanged();
通知 RecyclerView.Adapter 有数据改变。
private List<SimpleArticleItem> mArticleList = new ArrayList<SimpleArticleItem>();
class ArticleTask extends AsyncTask<Integer, Void, List<SimpleArticleItem>> {
private Context mContext;
public ArticleTask(Context context) {
mContext = context;
}
/**
* Runs on the UI thread before {@link #doInBackground}.
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
if (mArticleList != null && mArticleList.size() > 0) {
mArticleList.add(null);
// notifyItemInserted(int position)。这种方法是在第position位置
// 被插入了一条数据的时候能够使用这种方法刷新,
// 注意这种方法调用后会有插入的动画,这个动画能够使用默认的,也能够自定义。
mAdapter.notifyItemInserted(mArticleList.size() - 1);
}
}
/**
* @param params 偏移量 aid
* @return
*/
@Override
protected List<SimpleArticleItem> doInBackground(Integer... params) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return getArticleList(mColumn, params[0]);
}
@Override
protected void onPostExecute(final List<SimpleArticleItem> moreArticles) {
// 新增新闻数据
super.onPostExecute(moreArticles);
if (mArticleList.size() == 0) {
mArticleList.addAll(moreArticles);
mAdapter.notifyDataSetChanged();
} else {
//删除 footer
mArticleList.remove(mArticleList.size() - 1);
mArticleList.addAll(moreArticles);
mAdapter.notifyDataSetChanged();
loading = false;
}
}
}
Override RecyclerView.Adapter 中的 getItemViewType
extends RecyclerView.Adapter<RecyclerView.ViewHolder>
假设是null,返回Footer的Type;否则。返回正常新闻的Type。
本文,为了UI美观,把新闻分为两种:大于3幅图片 、小于3幅图片,对应返回不同的Type和ViewHolder。
public final static int TYPE_MULTI_IMAGES = 2; // 多个图片的文章
public final static int TYPE_FOOTER = 3;//底部--往往是loading_more
public final static int TYPE_NORMAL = 1; // 正常的一条文章
@Override
public int getItemViewType(int position) {
SimpleArticleItem article = articleList.get(position);
if (article == null) {
return TYPE_FOOTER;
} else if (article.getImageUrls().length >= 3) {
return TYPE_MULTI_IMAGES;
} else {
return TYPE_NORMAL;
}
}
Override RecyclerView.Adapter 中的 onCreateViewHolder
在该方法中利用 switch (viewType)
返回不同的xml布局文件及ViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder vh;
View view;
switch (viewType) {
//其它无法处理的情况使用viewholder_article_simple
default:
case TYPE_NORMAL:
view = mLayoutInflater.inflate(
R.layout.item_article_normal, parent, false);
vh = new ItemArticleViewHolder(view);
return vh;
case TYPE_FOOTER:
view = mLayoutInflater.inflate(
R.layout.recyclerview_footer, parent, false);
vh = new FooterViewHolder(view);
return vh;
case TYPE_MULTI_IMAGES:
view = mLayoutInflater.inflate(
R.layout.item_article_multi_images, parent, false);
vh = new MultiImagesViewHolder(view);
return vh;
}
}
Override RecyclerView.Adapter 中的 onBindViewHolder
利用 instanceof 推断是何种类型的ViewHolder。来给控件赋值、绑定数据。
注意:由于Footer是用null表示的,为了防止NullPointerException,
我们先用if把FooterViewHolder的情况处理了。
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
//这时候 article是 null。先把 footer 处理了
if (holder instanceof FooterViewHolder) {
((FooterViewHolder) holder).rcvLoadMore.spin();
return;
}
SimpleArticleItem article = articleList.get(position);
String[] imageUrls = article.getImageUrls();
if (holder instanceof ItemArticleViewHolder) {
ItemArticleViewHolder newHolder = (ItemArticleViewHolder) holder;
newHolder.rcvArticleTitle.setText(article.getTitle());
newHolder.rcvArticleDate.setText(article.getPublishDate());
//当图片小于3张时候 选取第1张图片
if (imageUrls.length > 0) {
newHolder.rcvArticlePhoto.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME
+ imageUrls[0]));
} else {
newHolder.rcvArticlePhoto.setImageURI(Uri.parse(ApiUrl.randomImageUrl(article.getId())));
}
//注意这个阅读次数是 int 类型。须要转化为 String 类型
newHolder.rcvArticleReadtimes.setText("浏览: " + article.getReadTimes());
newHolder.rcvArticleSummary.setText(article.getSummary());
} else {
MultiImagesViewHolder newHolder = (MultiImagesViewHolder) holder;
newHolder.articleTitle.setText(article.getTitle());
newHolder.articlePic1.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME + imageUrls[0]));
newHolder.articlePic2.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME + imageUrls[1]));
newHolder.articlePic3.setImageURI(Uri.parse(Constant.BUCKET_HOST_NAME + imageUrls[2]));
newHolder.countPics.setText("图片: " + imageUrls.length);
newHolder.countRead.setText("浏览: " + article.getReadTimes());
}
}
下拉刷新和上拉载入很多其它的源代码地址(欢迎star) https://github.com/studychen/SeeNewsV2
本文链接 http://blog.csdn.net/never_cxb/article/details/50759109 转载请注明出处
一些坑
注意给RecyclerView setLayoutManager,不然RecyclerView可能不显示
// 1. get a reference to recyclerView
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);
// 2. set layoutManger
recyclerView.setLayoutManager(new LinearLayoutManager(this));
參考文章
Android实现RecyclerView的下拉刷新和上拉载入很多其它的更多相关文章
- Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理
RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...
- 实现RecyclerView下拉刷新和上拉加载更多以及RecyclerView线性、网格、瀑布流效果演示
实现RecyclerView下拉刷新和上拉加载更多以及RecyclerView线性.网格.瀑布流效果演示 效果预览 实例APP 小米应用商店 使用方法 build.gradle文件 dependenc ...
- 使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉载入很多其它
一.概述 本篇博客介绍的是怎样使用SwipeRefreshLayout和RecyclerView实现高仿简书Android端的下拉刷新和上拉载入很多其它的效果. 依据效果图能够发现,本案例实现了例如以 ...
- 手把手教你实现RecyclerView的下拉刷新和上拉加载更多
手把手教你实现RecyclerView的下拉刷新和上拉加载更多 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...
- RecyclerView下拉刷新和上拉加载更多实现
RecyclerView下拉刷新和上拉加载更多实现 转 https://www.jianshu.com/p/4ea7c2d95ecf 在Android开发中,RecyclerView算是使用频率非 ...
- Android 使用PullToRefresh实现下拉刷新和上拉加载(ExpandableListView)
PullToRefresh是一套实现非常好的下拉刷新库,它支持: 1.ListView 2.ExpandableListView 3.GridView 4.WebView 等多种常用的需要刷新的Vie ...
- Diycode开源项目 搭建可以具有下拉刷新和上拉加载的Fragment
1.效果预览 1.1.这个首页就是一个Fragment碎片,本文讲述的就是这个碎片的搭建方式. 下拉会有一个旋转的刷新圈,上拉会刷新数据. 1.2.整体结构 首先底层的是BaseFragment 然后 ...
- 使用PullToRefresh实现下拉刷新和上拉加载
使用PullToRefresh实现下拉刷新和上拉加载 分类: Android2013-12-20 15:51 78158人阅读 评论(91) 收藏 举报 Android下拉刷新上拉加载PullToRe ...
- 安卓开发笔记——关于开源组件PullToRefresh实现下拉刷新和上拉加载(一分钟搞定,超级简单)
前言 以前在实现ListView下拉刷新和上拉加载数据的时候都是去继承原生的ListView重写它的一些方法,实现起来非常繁杂,需要我们自己去给ListView定制下拉刷新和上拉加载的布局文件,然后添 ...
随机推荐
- 【软考5】解释型 or 编译型
导读:在上篇博客中,我们了解到,目前的编码语言经过不断的发展,已经经历了机器语言--汇编语言--高级语言的过程.虽然我们的编码语言在不停的升级,但作为计算机来说,它始终是一个只能理解0和1构成的机器语 ...
- iOS长按控件
前言 网上看到一个button的长按控件效果不错,一个菱形从中间向两边增大,研究了下 原理 上图红色是控件上面放了视图,从上到下分别是view,normalLable,highlightLabel,b ...
- 【Luogu】P1199三国游戏(博弈论)
题目链接 来看一波有理有据的分析 三牧小明的那篇 代码 #include<cstdio> #include<cctype> #include<algorithm> ...
- 周赛Problem 1108: 蛋糕(二分)
1108: 蛋糕 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 17 Solved: 4 Description 杨神打代码打得有点疲倦,于是他想要 ...
- BZOJ1925 [Sdoi2010]地精部落 【dp】
题目 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中Hi是1到N ...
- 北京集训TEST13——PA(Goodness)
题目: Description 桌面上放有 n 张卡牌.对于每张卡牌,一面是绿色的,另一面是红色的.卡牌的每一面都标有一个整数.对于卡牌a和卡牌b,卡牌a对卡牌b的好感度为卡牌a绿色面的数与卡牌b红色 ...
- Mysql 函数的应用
CREATE TABLE `code_generate_dd` ( `id` ) NOT NULL AUTO_INCREMENT COMMENT '主键', `first_code` ) NOT NU ...
- postman 快捷方式--启动图标
下载,解压,安装,(此安装位置在/opt) 1.创建全局变量,也就是在任何地方都可以执行postman,不用去到安装目录,执行 : sudo ln -s /opt/postman/Postman /u ...
- 在 Windows 下用 TDM-GCC(MinGW)开发 DLL 涉及到数据同步锁及 DLL 初始化终止化函数的问题
在 Windows 下用 TDM-GCC(MinGW)开发 DLL 如果要用到数据同步锁,理论上可以采用 Windows API 提供的临界区实现(需要用到的函数有 InitializeCritica ...
- 洛谷——P2819 图的m着色问题
P2819 图的m着色问题 题目背景 给定无向连通图G和m种不同的颜色.用这些颜色为图G的各顶点着色,每个顶点着一种颜色.如果有一种着色法使G中每条边的2个顶点着不同颜色,则称这个图是m可着色的.图的 ...