關(guān)于Graywater的系列文章
- RecyclerView的超強(qiáng)輔助Graywater——理論篇
- RecyclerView的超強(qiáng)輔助Graywater——基礎(chǔ)實操篇
- RecyclerView的超強(qiáng)輔助Graywater——點(diǎn)擊事件
- RecyclerView的超強(qiáng)輔助Graywater——綜合實操篇
看到上一篇Graywater文章是11月8日寫的,也是拖很久了,這篇是Graywater系列文章最后一篇完結(jié)篇,把自己挖的坑給填了。
這篇文章是Graywater綜合練習(xí)文章,包括了復(fù)雜視圖、基本增刪改功能的實現(xiàn),文末附有Demo地址,同樣Demo也只是起一個拋磚引玉的作用,實際上還有很大的延展空間。
先上Demo效果圖:

老規(guī)矩,還是先說說本文目錄:
1. 復(fù)雜視圖的實現(xiàn)
2. 數(shù)據(jù)的插入
3. 數(shù)據(jù)的刪除
4. 數(shù)據(jù)的更新
5. 注意點(diǎn)
1. 復(fù)雜視圖的實現(xiàn)
從GIF圖中可以看到,該RecyclerView分為2大模塊,娛樂新聞模塊和體育新聞模塊,每個模塊對應(yīng)一個數(shù)據(jù)源Primitive和一個管理器ItemBinder,數(shù)據(jù)源就對應(yīng)了該模塊所有數(shù)據(jù)內(nèi)容,管理器對該模塊所有視圖進(jìn)行管理。
比如娛樂新聞模塊對應(yīng)了一個EntertainPrimitive和EntertainItemBinder,包含了該模塊的所有數(shù)據(jù),同時還包含了娛樂新聞標(biāo)題Binder和娛樂新聞內(nèi)容的Binder(娛樂新聞內(nèi)容的Binder使用List集合保存)。

接著往下看,在RecyclerView里有3種視圖:標(biāo)題視圖、娛樂新聞視圖、體育新聞視圖。每種視圖都有一組自己對應(yīng)的Binder、ViewHolder和ViewHolderCreator以及自己的布局文件。
看看實現(xiàn)娛樂新聞視圖的核心代碼:
EntertainItemBinder.java
@NonNull
@Override
public List<GraywaterAdapter.Binder<? super EntertainPrimitive, ? extends PrimitiveViewHolder>> getBinderList(@NonNull final EntertainPrimitive model, int position) {
return new ArrayList<GraywaterAdapter.Binder<? super EntertainPrimitive, ? extends PrimitiveViewHolder>>() {{
add(titleBinder); //添加娛樂新聞標(biāo)題
for (EntertainItem entertainItem : model.getEntertainItems()) {
add(entertainBinder); //添加娛樂新聞內(nèi)容
}
}};
}
所以在ItemBinder中可以添加多種類型的binder,就可以實現(xiàn)不同的視圖了。
2. 數(shù)據(jù)的插入
插入娛樂新聞的核心代碼:
@Override
public void onClickaddNews(String type) {
Toast.makeText(this, "add " + type + " success", Toast.LENGTH_SHORT).show();
switch (type) {
case TYPE_ENTERTAIN:
addEntertainNews();
mPrimitiveAdapter.remove(POS_ENTERTAIN);
mPrimitiveAdapter.add(POS_ENTERTAIN, mEntertainPrimitive);
//不需要mPrimitiveAdapter.notifyDataSetChanged();在add()方法中已經(jīng)包含了更新操作
break;
case TYPE_SPORT:
addSportNews();
mPrimitiveAdapter.remove(POS_SPORT);
mPrimitiveAdapter.add(POS_SPORT, mSportPrimitive);
break;
}
}
private void addEntertainNews() {
if (entertainItems == null) {
entertainItems = new ArrayList<>();
}
EntertainItem entertain = new EntertainItem();
entertain.setId("" + (entertainItems.size() + 1));
entertain.setUrl("https://img8.ccnxs.cn/uploadfile/hbase/201901/0129/HBC5C4FABFA51855.png");
entertain.setTitle("item " + (entertainItems.size() + 1) + " : " + "胡海泉獨(dú)自現(xiàn)身麗江 面帶微笑任拍照");
entertainItems.add(entertain);
}
3. 數(shù)據(jù)的刪除
刪除娛樂新聞的核心代碼:
@Override
public void onClickDeleteEntertain(EntertainItem entertain) {
boolean needRefresh = false;
Iterator iterator = entertainItems.iterator();
while (iterator.hasNext()) {
EntertainItem entertainItem = (EntertainItem) iterator.next();
if (entertainItem.getId().equals(entertain.getId())) {
iterator.remove();
needRefresh = true;
break;
}
}
if (needRefresh) {
mPrimitiveAdapter.remove(POS_ENTERTAIN);
mPrimitiveAdapter.add(POS_ENTERTAIN, mEntertainPrimitive);
}
}
4. 數(shù)據(jù)的更新
更新娛樂新聞的核心代碼:
點(diǎn)擊娛樂新聞跳轉(zhuǎn)到編輯頁進(jìn)行編輯,編輯成功返回MainActivity,在onActivityResult()方法中進(jìn)行處理,實際上娛樂新聞和體育新聞的編輯是不應(yīng)該放在同一個編輯頁的,我這里圖方便就寫在一起了。
@Override
public void onClickEditEntertain(EntertainItem entertain) {
Intent intent = new Intent(this, EditActivity.class);
intent.putExtra("type", TYPE_ENTERTAIN);
intent.putExtra("obj", entertain);
startActivityForResult(intent, 11);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (resultCode) {
case 100:
String type = data.getStringExtra("type");
if (MainActivity.TYPE_ENTERTAIN.equals(type)) {
updateEntertainItem((EntertainItem) data.getSerializableExtra("obj"));
} else {
updateSportItem((SportItem) data.getSerializableExtra("obj"));
}
break;
}
}
private void updateEntertainItem(EntertainItem item) {
boolean needRefresh = false;
Iterator iterator = entertainItems.iterator();
while (iterator.hasNext()) {
EntertainItem entertainItem = (EntertainItem) iterator.next();
if (entertainItem.getId().equals(item.getId())) {
entertainItem.setTitle(item.getTitle());
needRefresh = true;
break;
}
}
if (needRefresh) {
mPrimitiveAdapter.remove(POS_ENTERTAIN);
mPrimitiveAdapter.add(POS_ENTERTAIN, mEntertainPrimitive);
}
}
5. 注意點(diǎn)
· binderIndex
看一下娛樂新聞內(nèi)容EntertainBinder中的關(guān)鍵代碼
@Override
public void bind(@NonNull EntertainPrimitive model, @NonNull EntertainViewHolder holder, @NonNull List<GraywaterAdapter.Binder<? super EntertainPrimitive, ? extends EntertainViewHolder>>
binders, int binderIndex, @NonNull GraywaterAdapter.ActionListener<EntertainPrimitive, EntertainViewHolder> actionListener) {
EntertainItem entertain = model.getEntertainItems().get(binderIndex - 1); //因為第一個數(shù)據(jù)是新聞標(biāo)題,所以新聞內(nèi)容數(shù)據(jù)獲取時要減一
Picasso.get().load(entertain.getUrl()).placeholder(R.mipmap.ic_launcher).into(holder.getImg());
holder.getTitle().setText(entertain.getTitle());
holder.getmActionListenerDelegate().update(actionListener, model, holder, binders, binderIndex, null);
holder.getMainLayoutView().setOnClickListener(holder.getmActionListenerDelegate());
holder.getDelete().setOnClickListener(holder.getmActionListenerDelegate());
}
注意這句代碼:
EntertainItem entertain = model.getEntertainItems().get(binderIndex - 1);
有沒有疑惑為什么要binderIndex要減1?上文也提到EntertainItemBinder是對標(biāo)題和內(nèi)容統(tǒng)一進(jìn)行管理,而binderIndex返回的是binder的下標(biāo)??匆幌聰帱c(diǎn)截圖就明白了:

因為包含了標(biāo)題TitleBinder,所以第一條新聞內(nèi)容對應(yīng)的binderIndex對應(yīng)的下標(biāo)是1,但新聞內(nèi)容的數(shù)據(jù)集合與新聞標(biāo)題的數(shù)據(jù)是相互獨(dú)立,沒有關(guān)系的,所以第一條新聞內(nèi)容在數(shù)據(jù)集合中的位置是0,所以binderIndex需要減1。
補(bǔ)充:
如果對你有幫助的話,點(diǎn)贊、評論、贊賞都是對我的鼓勵,也是支持我寫下去的動力,謝謝!