前言:
正在做一个资讯类app,打算一边做一边整理,供自己学习与巩固。用到的知识复杂度不高,仅适于新手。经验不多,如果写出来的代码有不好的地方欢迎讨论。
以往的内容
第六章 加载更多
本章内容最终效果:
加载更多效果.gif加载更多效果3.gif
知识点:
RecyclerView.ViewHolder
学习目标:
1、使用RecyclerView的适配器Adapter来加载不同布局。
2、使用RecyclerView的OnScrollListener来判断列表状态。
前五章的数据展示内容是有限的,滑到底部后就不再加载,本章内容将完成新闻模块用户上滑到底部加载更多的功能,其它模块上滑解决思路与新闻模块相同,交由章节任务里完成,本章不重复讲解。
项目实战:
注意
本章用到的drawable资源、values资源皆存放在百度网盘
(请将values文件夹中的style.xml或color.xml更新一致后再运行,如有后续更新自行修改)
1.1用到的Api:
新闻模块:
http://c.m.163.com/nc/article/headline/T1348647909107/20-20.html
新闻模块在startPage的地方设置为20或以上的数字,返回的数据就能达到加载更多的效果。
image.png电影模块:
https://api.douban.com/v2/movie/in_theaters?start=20
电影模块需要添加应该参数start,这是在前面的电影模块里没有的。
视频模块:
视频模块的数据只要加载一次就会刷新一次,所以需要加载更多的时候正常加载就好了。
1.2 正在加载状态显示
上滑加载更多有很多种写法,这里我们用的是在适配器改变RecyclerView的ViewHolder的方法。
首先我们新建一个布局文件,命名为footer.xml
footer.xml
<?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="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:id="@+id/ll_footer">
<ProgressBar
android:layout_width="40dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="@+id/pb_footer"
style="@style/common_mProgress_circle"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_margin="15dp"
android:gravity="center"
android:text="正在加载......"/>
</LinearLayout>
接下来是最麻烦的Adapter代码了。
在ItemNewsAdapter中,我们onCreateViewHolder直接写死返回ItemNewsHolder,这种做法不够灵活。
修改前我们需要将它修改成RecyclerView.ViewHolder
image.png单是这样还不够,我们还要在onBindViewHolder中判断此时用的是哪个ViewHolder。
image.png上面所做的一切,都是为了能让RecyclerView加载不同的布局。
我们来写一个Footer的ViewHolder。
image.png
然后我们需要在列表拉倒底部时显示它,是否拉到底部我们用自定义ViewType来判断。
重写getItemViewType方法
image.png然后在onCreateViewHolder中加上判断
image.pngItemNewsAdapter的代码:
public class ItemNewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<NewsBean.Bean> objects = new ArrayList<NewsBean.Bean>();
private Context context;
public ItemNewsAdapter(Context context) {
this.context = context;
}
public void setData(List<NewsBean.Bean> objects) {
this.objects = objects;
}
@Override
public int getItemViewType(int position) {
if (position + 1 == getItemCount()) {
return 1;
} else {
return 0;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_news, parent, false);
return new ItemNewsHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.footer, parent, false);
return new FooterHolder(view);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ItemNewsHolder) {
final NewsBean.Bean bean = objects.get(position);
if (bean == null) {
return;
}
Glide.with(context)
.load(bean.getImgsrc())
.into(((ItemNewsHolder) holder).ivNewsImg);
if (position == 0) {
((ItemNewsHolder) holder).tvNewsDigest.setVisibility(View.GONE);
((ItemNewsHolder) holder).tvNewsTitle.setText("图片:" + bean.getTitle());
} else {
((ItemNewsHolder) holder).tvNewsTitle.setText(bean.getTitle());
((ItemNewsHolder) holder).tvNewsDigest.setText(bean.getMtime() + " : " + bean.getDigest());
((ItemNewsHolder) holder).cvNews.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, ADetailActivity.class);
intent.putExtra("url", bean.getUrl());
intent.putExtra("title", bean.getTitle());
context.startActivity(intent);
}
});
}
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return objects.size();
}
protected class ItemNewsHolder extends RecyclerView.ViewHolder {
private ImageView ivNewsImg;
private TextView tvNewsTitle;
private TextView tvNewsDigest;
private CardView cvNews;
public ItemNewsHolder(View view) {
super(view);
ivNewsImg = (ImageView) view.findViewById(R.id.iv_news_img);
tvNewsTitle = (TextView) view.findViewById(R.id.tv_news_title);
tvNewsDigest = (TextView) view.findViewById(R.id.tv_news_digest);
cvNews = (CardView) view.findViewById(R.id.cv_news);
}
}
protected class FooterHolder extends RecyclerView.ViewHolder {
public FooterHolder(View itemView) {
super(itemView);
}
}
}
效果:
正在加载.gif1.3 Fragment
我们需要一个layoutManager来给我们判断列表是否达到底部,还有startPage来作为加载更多的参数。
image.png然后修改设置RecyclerView部分的代码。
image.png
写一个loadMore的方法,当执行时startPage+20:
image.png再给RecyclerView加上addOnScrollListener的设置。
image.png2.1 Model层
上面的操作只是完成了页面对列表状态的判断,相对的,数据获取层也需要添加一些方法对数据返回做回应。
Model层需要添加一个监听加载更多的方法:
INewsLoadListener.javaNewsModel对startPage的不同对应调用监听的方法也不同:
NewsModel.java2.2 View层
View层需要添加一个显示更多数据的方法:
INewsView.java2.3 Presenter层
Presenter层得补上刚刚Model层写的loadMoreSuccess方法:
NewsPresenter.java在加载更多的时候,上面SwipeRefreshLayout的圆形加载框就不要出现了,写一个判断区别它。
NewsPresenter.java3.1 数据添加
我们获取到加载更多的数据后,需要将它添加到recyclerView列表中,所以我们再Adapter中加上添加数据的方法:
ItemNewsAdapter.java做完上面步骤后,我们回到FgNewsListFragment,把View层添加的showMoreNews方法补上:
FgNewsListFragment.java在加载更多状态下,网络请求出错时,最好把正在加载的布局关掉,所以在showErrorMsg方法中,我们加上RecyclerView移除布局的代码:
FgNewsListFragment.java最终效果:
加载更多效果.gif出现错误时的效果:
加载更多效果2.gif
学习任务
把电影模块的加载更多、视频模块的加载更多也做出来。
电影模块效果:
只做了正在热映的加载更多,需要注意的是:
正在热映start超过40的时候返回的数据是空的,需要给用户作出判断并且提示“没有更多了”。
加载更多效果3.gif视频模块效果:
加载更多效果4.gif项目源码:https://github.com/Huigesi/IdleReaderDemo
上一章:
第五章 视频模块
网友评论