前言:
正在做一個(gè)資訊類app,打算一邊做一邊整理,供自己學(xué)習(xí)與鞏固哩盲。用到的知識(shí)復(fù)雜度不高前方,僅適于新手。經(jīng)驗(yàn)不多廉油,如果寫(xiě)出來(lái)的代碼有不好的地方歡迎討論惠险。
以往的內(nèi)容
第二章 retrofit獲取網(wǎng)絡(luò)數(shù)據(jù)
第六章 加載更多
本章內(nèi)容最終效果:
知識(shí)點(diǎn):
RecyclerView.ViewHolder
學(xué)習(xí)目標(biāo):
1、使用RecyclerView的適配器Adapter來(lái)加載不同布局抒线。
2班巩、使用RecyclerView的OnScrollListener來(lái)判斷列表狀態(tài)。
前五章的數(shù)據(jù)展示內(nèi)容是有限的嘶炭,滑到底部后就不再加載抱慌,本章內(nèi)容將完成新聞模塊用戶上滑到底部加載更多的功能,其它模塊上滑解決思路與新聞模塊相同眨猎,交由章節(jié)任務(wù)里完成抑进,本章不重復(fù)講解。
項(xiàng)目實(shí)戰(zhàn):
注意
本章用到的drawable資源睡陪、values資源皆存放在百度網(wǎng)盤(pán)
(請(qǐng)將values文件夾中的style.xml或color.xml更新一致后再運(yùn)行寺渗,如有后續(xù)更新自行修改)
1.1用到的Api:
新聞模塊:
http://c.m.163.com/nc/article/headline/T1348647909107/20-20.html
新聞模塊在startPage的地方設(shè)置為20或以上的數(shù)字,返回的數(shù)據(jù)就能達(dá)到加載更多的效果兰迫。
電影模塊:
https://api.douban.com/v2/movie/in_theaters?start=20
電影模塊需要添加應(yīng)該參數(shù)start户秤,這是在前面的電影模塊里沒(méi)有的。
視頻模塊:
視頻模塊的數(shù)據(jù)只要加載一次就會(huì)刷新一次逮矛,所以需要加載更多的時(shí)候正常加載就好了。
1.2 正在加載狀態(tài)顯示
上滑加載更多有很多種寫(xiě)法转砖,這里我們用的是在適配器改變RecyclerView的ViewHolder的方法须鼎。
首先我們新建一個(gè)布局文件,命名為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>
接下來(lái)是最麻煩的Adapter代碼了府蔗。
在ItemNewsAdapter中晋控,我們onCreateViewHolder直接寫(xiě)死返回ItemNewsHolder,這種做法不夠靈活姓赤。
我們需要將它修改成RecyclerView.ViewHolder
單是這樣還不夠赡译,我們還要在onBindViewHolder中判斷此時(shí)用的是哪個(gè)ViewHolder。
上面所做的一切不铆,都是為了能讓RecyclerView加載不同的布局蝌焚。
我們來(lái)寫(xiě)一個(gè)Footer的ViewHolder裹唆。
然后我們需要在列表拉倒底部時(shí)顯示它,是否拉到底部我們用自定義ViewType來(lái)判斷只洒。
重寫(xiě)getItemViewType方法
然后在onCreateViewHolder中加上判斷
ItemNewsAdapter的代碼:
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);
}
}
}
效果:
1.3 Fragment
我們需要一個(gè)layoutManager來(lái)給我們判斷列表是否達(dá)到底部许帐,還有startPage來(lái)作為加載更多的參數(shù)。
然后修改設(shè)置RecyclerView部分的代碼毕谴。
寫(xiě)一個(gè)loadMore的方法成畦,當(dāng)執(zhí)行時(shí)startPage+20:
再給RecyclerView加上addOnScrollListener的設(shè)置。
2.1 Model層
上面的操作只是完成了頁(yè)面對(duì)列表狀態(tài)的判斷涝开,相對(duì)的循帐,數(shù)據(jù)獲取層也需要添加一些方法對(duì)數(shù)據(jù)返回做回應(yīng)。
Model層需要添加一個(gè)監(jiān)聽(tīng)加載更多的方法:
NewsModel對(duì)startPage的不同對(duì)應(yīng)調(diào)用監(jiān)聽(tīng)的方法也不同:
2.2 View層
View層需要添加一個(gè)顯示更多數(shù)據(jù)的方法:
2.3 Presenter層
Presenter層得補(bǔ)上剛剛Model層寫(xiě)的loadMoreSuccess方法:
在加載更多的時(shí)候舀武,上面SwipeRefreshLayout的圓形加載框就不要出現(xiàn)了拄养,寫(xiě)一個(gè)判斷區(qū)別它。
3.1 數(shù)據(jù)添加
我們獲取到加載更多的數(shù)據(jù)后奕剃,需要將它添加到recyclerView列表中衷旅,所以我們?cè)貯dapter中加上添加數(shù)據(jù)的方法:
做完上面步驟后,我們回到FgNewsListFragment纵朋,把View層添加的showMoreNews方法補(bǔ)上:
在加載更多狀態(tài)下柿顶,網(wǎng)絡(luò)請(qǐng)求出錯(cuò)時(shí),最好把正在加載的布局關(guān)掉操软,所以在showErrorMsg方法中嘁锯,我們加上RecyclerView移除布局的代碼:
最終效果:
出現(xiàn)錯(cuò)誤時(shí)的效果:
學(xué)習(xí)任務(wù)
把電影模塊的加載更多、視頻模塊的加載更多也做出來(lái)聂薪。
電影模塊效果:
只做了正在熱映的加載更多家乘,需要注意的是:
正在熱映start超過(guò)40的時(shí)候返回的數(shù)據(jù)是空的,需要給用戶作出判斷并且提示“沒(méi)有更多了”藏澳。
視頻模塊效果:
項(xiàng)目源碼:https://github.com/Huigesi/IdleReaderDemo
上一章:
第五章 視頻模塊