摘要:,無(wú)法復(fù)用,假如有多個(gè)頁(yè)面有多個(gè),那么就要寫(xiě)多個(gè)。綁定,主要作用是綁定數(shù)據(jù)到正確的視圖上??删S護(hù)性不同的列表類(lèi)型由添加處理,哪怕添加多個(gè),相互之間互不干擾,代碼簡(jiǎn)潔,維護(hù)成本低。
目錄介紹
01.先看看實(shí)際需求
02.adapter實(shí)現(xiàn)多個(gè)type
03.這樣寫(xiě)的弊端
04.如何優(yōu)雅實(shí)現(xiàn)adapter封裝
好消息博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開(kāi)發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長(zhǎng)期更新維護(hù)并且修正,持續(xù)完善……開(kāi)源的文件是markdown格式的!同時(shí)也開(kāi)源了生活博客,從12年起,積累共計(jì)N篇[近100萬(wàn)字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請(qǐng)注明出處,謝謝!
鏈接地址:https://github.com/yangchong2...
如果覺(jué)得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬(wàn)事起于忽微,量變引起質(zhì)變!
01.先看看實(shí)際需求比如一個(gè)APP的首頁(yè),包含Banner區(qū)、廣告區(qū)、文本內(nèi)容、圖片內(nèi)容、新聞內(nèi)容等等。
RecyclerView 可以用ViewType來(lái)區(qū)分不同的item,也可以滿足需求,但還是存在一些問(wèn)題,比如:
1,在item過(guò)多邏輯復(fù)雜列表界面,Adapter里面的代碼量龐大,邏輯復(fù)雜,后期難以維護(hù)。
2,每次增加一個(gè)列表都需要增加一個(gè)Adapter,重復(fù)搬磚,效率低下。
3,無(wú)法復(fù)用adapter,假如有多個(gè)頁(yè)面有多個(gè)type,那么就要寫(xiě)多個(gè)adapter。
4,要是有局部刷新,那么就比較麻煩了,比如廣告區(qū)也是一個(gè)九宮格的RecyclerView,點(diǎn)擊局部刷新當(dāng)前數(shù)據(jù),比較麻煩。
02.adapter實(shí)現(xiàn)多個(gè)type
通常寫(xiě)一個(gè)多Item列表的方法
根據(jù)不同的ViewType 處理不同的item,如果邏輯復(fù)雜,這個(gè)類(lèi)的代碼量是很龐大的。如果版本迭代添加新的需求,修改代碼很麻煩,后期維護(hù)困難。
主要操作步驟
在onCreateViewHolder中根據(jù)viewType參數(shù),也就是getItemViewType的返回值來(lái)判斷需要?jiǎng)?chuàng)建的ViewHolder類(lèi)型
在onBindViewHolder方法中對(duì)ViewHolder的具體類(lèi)型進(jìn)行判斷,分別為不同類(lèi)型的ViewHolder進(jìn)行綁定數(shù)據(jù)與邏輯處理
代碼如下所示
public class HomePageAdapter extends RecyclerView.Adapter { public static final int TYPE_BANNER = 0; public static final int TYPE_AD = 1; public static final int TYPE_TEXT = 2; public static final int TYPE_IMAGE = 3; public static final int TYPE_NEW = 4; private List03.這樣寫(xiě)的弊端mData; public void setData(List data) { mData = data; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType){ case TYPE_BANNER: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_banner_layout,null)); case TYPE_AD: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_ad_item_layout,null)); case TYPE_TEXT: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_text_item_layout,null)); case TYPE_IMAGE: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_image_item_layout,null)); case TYPE_NEW: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_news_item_layout,null)); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int type = getItemViewType(position); switch (type){ case TYPE_BANNER: // banner 邏輯處理 break; case TYPE_AD: // 廣告邏輯處理 break; case TYPE_TEXT: // 文本邏輯處理 break; case TYPE_IMAGE: //圖片邏輯處理 break; case TYPE_NEW: //視頻邏輯處理 break; // ... 此處省去N行代碼 } } @Override public int getItemViewType(int position) { if(position == 0){ return TYPE_BANNER;//banner在開(kāi)頭 }else { return mData.get(position).type;//type 的值為T(mén)YPE_AD,TYPE_IMAGE,TYPE_AD,等其中一個(gè) } } @Override public int getItemCount() { return mData == null ? 0:mData.size(); } public static class BannerViewHolder extends RecyclerView.ViewHolder{ public BannerViewHolder(View itemView) { super(itemView); //綁定控件 } } public static class NewViewHolder extends RecyclerView.ViewHolder{ public VideoViewHolder(View itemView) { super(itemView); //綁定控件 } } public static class AdViewHolder extends RecyclerView.ViewHolder{ public AdViewHolder(View itemView) { super(itemView); //綁定控件 } } public static class TextViewHolder extends RecyclerView.ViewHolder{ public TextViewHolder(View itemView) { super(itemView); //綁定控件 } } public static class ImageViewHolder extends RecyclerView.ViewHolder{ public ImageViewHolder(View itemView) { super(itemView); //綁定控件 } } }
上面那樣寫(xiě)的弊端
類(lèi)型檢查與類(lèi)型轉(zhuǎn)型,由于在onCreateViewHolder根據(jù)不同類(lèi)型創(chuàng)建了不同的ViewHolder,所以在onBindViewHolder需要針對(duì)不同類(lèi)型的ViewHolder進(jìn)行數(shù)據(jù)綁定與邏輯處理,這導(dǎo)致需要通過(guò)instanceof對(duì)ViewHolder進(jìn)行類(lèi)型檢查與類(lèi)型轉(zhuǎn)型。
不利于擴(kuò)展,目前的需求是列表中存在5種布局類(lèi)類(lèi)型,那么如果需求變動(dòng),極端一點(diǎn)的情況就是數(shù)據(jù)源是從服務(wù)器獲取的,數(shù)據(jù)中的model決定列表中的布局類(lèi)型。這種情況下,每當(dāng)model改變或model類(lèi)型增加,我們都要去改變adapter中很多的代碼,同時(shí)Adapter還必須知道特定的model在列表中的位置(position)除非跟服務(wù)端約定好,model(位置)不變,很顯然,這是不現(xiàn)實(shí)的。
不利于維護(hù),這點(diǎn)應(yīng)該是上一點(diǎn)的延伸,隨著列表中布局類(lèi)型的增加與變更,getItemViewType、onCreateViewHolder、onBindViewHolder中的代碼都需要變更或增加,Adapter 中的代碼會(huì)變得臃腫與混亂,增加了代碼的維護(hù)成本。
04.如何優(yōu)雅實(shí)現(xiàn)adapter封裝
核心目的就是三個(gè)
避免類(lèi)的類(lèi)型檢查與類(lèi)型轉(zhuǎn)型
增強(qiáng)Adapter的擴(kuò)展性
增強(qiáng)Adapter的可維護(hù)性
當(dāng)列表中類(lèi)型增加或減少時(shí)Adapter中主要改動(dòng)的就是getItemViewType、onCreateViewHolder、onBindViewHolder這三個(gè)方法,因此,我們就從這三個(gè)方法中開(kāi)始著手。
既然可能存在多個(gè)type類(lèi)型的view,那么能不能把這些比如banner,廣告,文本,視頻,新聞等當(dāng)做一個(gè)HeaderView來(lái)操作。
在getItemViewType方法中。
減少if之類(lèi)的邏輯判斷簡(jiǎn)化代碼,可以簡(jiǎn)單粗暴的用hashCode作為增加type標(biāo)識(shí)。
通過(guò)創(chuàng)建列表的布局類(lèi)型,同時(shí)返回的不再是簡(jiǎn)單的布局類(lèi)型標(biāo)識(shí),而是布局的hashCode值
private ArrayListheaders = new ArrayList<>(); public interface InterItemView { /** * 創(chuàng)建view * @param parent parent * @return view */ View onCreateView(ViewGroup parent); /** * 綁定view * @param headerView headerView */ void onBindView(View headerView); } /** * 獲取類(lèi)型,主要作用是用來(lái)獲取當(dāng)前項(xiàng)Item(position參數(shù))是哪種類(lèi)型的布局 * @param position 索引 * @return int */ @Deprecated @Override public final int getItemViewType(int position) { if (headers.size()!=0){ if (position = 0){ return footers.get(i).hashCode(); } } return getViewType(position-headers.size()); }
onCreateViewHolder
getItemViewType返回的是布局hashCode值,也就是onCreateViewHolder(ViewGroup parent, int viewType)參數(shù)中的viewType
/** * 創(chuàng)建viewHolder,主要作用是創(chuàng)建Item視圖,并返回相應(yīng)的ViewHolder * @param parent parent * @param viewType type類(lèi)型 * @return 返回viewHolder */ @NonNull @Override public final BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = createViewByType(parent, viewType); if (view!=null){ return new BaseViewHolder(view); } final BaseViewHolder viewHolder = OnCreateViewHolder(parent, viewType); setOnClickListener(viewHolder); return viewHolder; } private View createViewByType(ViewGroup parent, int viewType){ for (InterItemView headerView : headers){ if (headerView.hashCode() == viewType){ View view = headerView.onCreateView(parent); StaggeredGridLayoutManager.LayoutParams layoutParams; if (view.getLayoutParams()!=null) { layoutParams = new StaggeredGridLayoutManager.LayoutParams(view.getLayoutParams()); } else { layoutParams = new StaggeredGridLayoutManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } layoutParams.setFullSpan(true); view.setLayoutParams(layoutParams); return view; } } for (InterItemView footerView : footers){ if (footerView.hashCode() == viewType){ View view = footerView.onCreateView(parent); StaggeredGridLayoutManager.LayoutParams layoutParams; if (view.getLayoutParams()!=null) { layoutParams = new StaggeredGridLayoutManager.LayoutParams(view.getLayoutParams()); } else { layoutParams = new StaggeredGridLayoutManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } layoutParams.setFullSpan(true); view.setLayoutParams(layoutParams); return view; } } return null; }
在onBindViewHolder方法中??梢钥吹?,在此方法中,添加一種header類(lèi)型的view,則通過(guò)onBindView進(jìn)行數(shù)據(jù)綁定。
/** * 綁定viewHolder,主要作用是綁定數(shù)據(jù)到正確的Item視圖上。當(dāng)視圖從不可見(jiàn)到可見(jiàn)的時(shí)候,會(huì)調(diào)用這個(gè)方法。 * @param holder holder
*/ @Override public final void onBindViewHolder(BaseViewHolder holder, int position) { holder.itemView.setId(position); if (headers.size()!=0 && position=0){ footers.get(i).onBindView(holder.itemView); return ; } OnBindViewHolder(holder,position-headers.size()); } ```
如何使用,如下所示,這個(gè)就是banner類(lèi)型,可以說(shuō)是解耦了之前adapter中復(fù)雜的操作
InterItemView interItemView = new InterItemView() { @Override public View onCreateView(ViewGroup parent) { BannerView header = new BannerView(HeaderFooterActivity.this); header.setHintView(new ColorPointHintView(HeaderFooterActivity.this, Color.YELLOW, Color.GRAY)); header.setHintPadding(0, 0, 0, (int) AppUtils.convertDpToPixel( 8, HeaderFooterActivity.this)); header.setPlayDelay(2000); header.setLayoutParams(new RecyclerView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, (int) AppUtils.convertDpToPixel(200, HeaderFooterActivity.this))); header.setAdapter(new BannerAdapter(HeaderFooterActivity.this)); return header; } @Override public void onBindView(View headerView) { } }; adapter.addHeader(interItemView);
封裝后好處
拓展性——Adapter并不關(guān)心不同的列表類(lèi)型在列表中的位置,因此對(duì)于Adapter來(lái)說(shuō)列表類(lèi)型可以隨意增加或減少。十分方便,同時(shí)設(shè)置類(lèi)型view的布局和數(shù)據(jù)綁定都不需要在adapter中處理。充分解耦。
可維護(hù)性——不同的列表類(lèi)型由adapter添加headerView處理,哪怕添加多個(gè)headerView,相互之間互不干擾,代碼簡(jiǎn)潔,維護(hù)成本低。
其他介紹 01.關(guān)于博客匯總鏈接1.技術(shù)博客匯總
2.開(kāi)源項(xiàng)目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn
github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡(jiǎn)書(shū):http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽(tīng)書(shū):http://www.ximalaya.com/zhubo...
開(kāi)源中國(guó):https://my.oschina.net/zbj161...
泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault頭條:https://segmentfault.com/u/xi...
掘金:https://juejin.im/user/593943...
項(xiàng)目案例地址:https://github.com/yangchong2...文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74797.html
摘要:支持復(fù)雜頁(yè)面,例如添加自定義頭部和底部布局,支持橫向滑動(dòng),還可以支持粘貼頭部類(lèi)似微信好友分組,支持不規(guī)則瀑布流效果,支持側(cè)滑刪除功能。十分方便實(shí)現(xiàn)復(fù)雜的布局頁(yè)面,結(jié)構(gòu)上層次分明,便于維護(hù)。 目錄介紹 1.復(fù)雜頁(yè)面庫(kù)介紹 2.本庫(kù)優(yōu)勢(shì)亮點(diǎn) 2.1 支持多種狀態(tài)切換管理 2.2 支持添加多個(gè)header和footer 2.3 支持側(cè)滑功能和拖拽移動(dòng) 2.4 其他亮點(diǎn)介紹 3.如...
摘要:缺點(diǎn)自動(dòng)裝箱的存在意味著每一次插入都會(huì)有額外的對(duì)象創(chuàng)建。對(duì)象本身是一層額外需要被創(chuàng)建以及被垃圾回收的對(duì)象。相較于我們舍棄了和類(lèi)型的放棄了并依賴(lài)于二分法查找。 目錄介紹 25.0.0.0 請(qǐng)說(shuō)一下RecyclerView?adapter的作用是什么,幾個(gè)方法是做什么用的?如何理解adapter訂閱者模式? 25.0.0.1 ViewHolder的作用是什么?如何理解ViewHolder...
摘要:支持復(fù)雜頁(yè)面,例如添加自定義頭部和底部布局,支持橫向滑動(dòng),還可以支持粘貼頭部類(lèi)似微信好友分組,支持不規(guī)則瀑布流效果,支持側(cè)滑刪除功能。支持粘貼頭部的需求效果,這種效果類(lèi)似微信好友分組的那種功能界面。 目錄介紹 1.復(fù)雜頁(yè)面庫(kù)介紹 2.本庫(kù)優(yōu)勢(shì)亮點(diǎn) 2.1 支持多種狀態(tài)切換管理 2.2 支持添加多個(gè)header和footer 2.3 支持側(cè)滑功能和拖拽移動(dòng) 2.4 其他亮點(diǎn)介紹 ...
摘要:是規(guī)則的瀑布流。普通的尺寸會(huì)出現(xiàn)錯(cuò)位的問(wèn)題索引這個(gè)是右邊這個(gè)是左邊間距解決辦法,可以通過(guò)里的來(lái)判斷,這個(gè)方法不管你高度怎樣,他都是左右左右開(kāi)始排列的。 目錄介紹 01.規(guī)則瀑布流實(shí)現(xiàn)02.不規(guī)則瀑布流實(shí)現(xiàn)2.1 實(shí)現(xiàn)方式2.2 遇到問(wèn)題03.瀑布流上拉加載04.給瀑布流設(shè)置分割線05.自定義Manager崩潰06.如何避免刷新抖動(dòng)07.為何有時(shí)出現(xiàn)跳動(dòng)08.瀑布流圖片優(yōu)化09.onBi...
摘要:此方法應(yīng)由實(shí)現(xiàn)使用,以獲取視圖來(lái)表示來(lái)自的數(shù)據(jù)。如果適配器沒(méi)有指示給定位置上的數(shù)據(jù)已更改,則回收程序?qū)L試發(fā)回一個(gè)以前為該數(shù)據(jù)初始化的報(bào)廢視圖,而不進(jìn)行重新綁定。如果它只附加了一個(gè)適配器,并且新適配器使用與不同的,則將清除其緩存。 目錄介紹 1.RecycleView的結(jié)構(gòu) 2.Adapter 2.1 RecyclerView.Adapter扮演的角色 2.2 重寫(xiě)的方法 2.3...
閱讀 2298·2021-11-15 11:37
閱讀 2972·2021-09-01 10:41
閱讀 800·2019-12-27 11:58
閱讀 756·2019-08-30 15:54
閱讀 723·2019-08-30 13:52
閱讀 2937·2019-08-29 12:22
閱讀 1082·2019-08-28 18:27
閱讀 1462·2019-08-26 18:42