Android開發(fā)可添加頭尾的RecycleView的實(shí)現(xiàn)
正文
界面編碼設(shè)計(jì)實(shí)現(xiàn)中,我們肯定會(huì)用到列表展示控件,大家肯定用過(guò)ListView。后來(lái)google推出了RecycleView,幫我們?nèi)プ隽撕芏鄡?yōu)化(內(nèi)置viewholder增加復(fù)用率、可以支持局部刷新、布局可以通過(guò)外層指定layout等),正常的使用,如下:
MyRecycleViewAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_decorator); Component component = new ConCreateComponent(); ComponentImplA impl1 = new ComponentImplA(component); impl1.operation(); List<String> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.add("position " + i); } adapter = new MyRecycleViewAdapter(this); adapter.setData(list); } /** * 原始的yRecycleViewAdapter v1 */ public void buttonv1(View view) { findViewById(R.id.recycleview).setVisibility(View.VISIBLE); findViewById(R.id.wrapperR).setVisibility(View.GONE); RecyclerView recyclerView = findViewById(R.id.recycleview); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); }
但是RecycleView大家發(fā)現(xiàn)有一個(gè)問(wèn)題,我們?nèi)绻胍獮檫@個(gè)RecycleView添加自定義的頭部view、尾部view的話,官方這個(gè)明顯做不到,那這時(shí)我們可以考慮用裝飾者模式或者繼承去擴(kuò)展一下。
設(shè)計(jì)UML圖
首先我們通過(guò)UML圖,來(lái)設(shè)計(jì)一下,設(shè)計(jì)之前想一下,我們是想要擴(kuò)展RecyclerView.Adapter和RecyclerView,從而可以實(shí)現(xiàn)addHeadView、addFootView的功能,那么需要以下幾步驟。
1)首先,由于RecyclerView.Adapter已經(jīng)是一個(gè)抽象類接口,我們自己繼承與它,然后進(jìn)行包裝定義為WrapperRecyclerAdapter類
2)WrapperRecyclerAdapter肯定要持有RecyclerView.Adapter的引用,所以需要有一個(gè)構(gòu)造方法,將RecyclerView.Adapter的引用傳遞進(jìn)來(lái)
3)由于WrapperRecyclerAdapter繼承與RecyclerView.Adapter,肯定要去實(shí)現(xiàn)關(guān)鍵的方法,onCreateViewHolder(創(chuàng)建viewitem的holder)、onBindViewHolder(viewholder數(shù)據(jù)綁定)、getItemCount(獲取列表item的數(shù)量)
4)關(guān)鍵的一步來(lái)了,就是使用RecyclerView.Adapter、footviews、headviews,這三者組合,重寫上面的三個(gè)重要方法,給列表相應(yīng)位置創(chuàng)建對(duì)應(yīng)的item
代碼實(shí)現(xiàn)1
WrapperRecyclerAdapter
package com.itbird.design.decorator.recycleview; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; /** * RecyclerView.Adapter包裝類,擴(kuò)展實(shí)現(xiàn)headView、footView的添加 * Created by itbird on 2022/6/10 */ public class WrapperRecyclerAdapter extends RecyclerView.Adapter { RecyclerView.Adapter adapter; List<View> headViews = new ArrayList<>(); List<View> footViews = new ArrayList<>(); public WrapperRecyclerAdapter(RecyclerView.Adapter adapter) { this.adapter = adapter; adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { notifyDataSetChanged(); } }); } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) { //頭部的,返回頭部的viewholder if (position < headViews.size()) { return new WrapperViewHolder(headViews.get(position)); } //adapter返回中間數(shù)據(jù)holder if (position >= headViews.size() && position < headViews.size() + adapter.getItemCount()) { return adapter.onCreateViewHolder(parent, adapter.getItemViewType(position - headViews.size())); } //尾部的,返回尾部的viewholder return new WrapperViewHolder(footViews.get(position - headViews.size() - adapter.getItemCount())); } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (position < headViews.size() || position >= adapter.getItemCount() + headViews.size()) { return; } //頭部和底部不需要做處理,只需要真實(shí)的adapter需要處理 adapter.onBindViewHolder(holder, position - headViews.size()); } @Override public int getItemViewType(int position) { return position; } @Override public int getItemCount() { return headViews.size() + footViews.size() + adapter.getItemCount(); } public void addHeadView(View view) { if (!headViews.contains(view)) { headViews.add(view); notifyDataSetChanged(); } } public void addFootView(View view) { if (!footViews.contains(view)) { footViews.add(view); notifyDataSetChanged(); } } public void removeHeadView(View view) { if (headViews.contains(view)) { headViews.add(view); notifyDataSetChanged(); } } public void removeFootView(View view) { if (footViews.contains(view)) { footViews.remove(view); notifyDataSetChanged(); } } static class WrapperViewHolder extends RecyclerView.ViewHolder { public WrapperViewHolder(@NonNull View itemView) { super(itemView); } } }
這時(shí)再去調(diào)用,發(fā)現(xiàn)就可以如下調(diào)用
/** * 擴(kuò)展的,可以增加頭尾的recycleview v2 */ public void buttonv2(View view) { findViewById(R.id.recycleview).setVisibility(View.VISIBLE); findViewById(R.id.wrapperR).setVisibility(View.GONE); RecyclerView recyclerView = findViewById(R.id.recycleview); recyclerView.setLayoutManager(new LinearLayoutManager(this)); WrapperRecyclerAdapter wrapperRecyclerAdapter = new WrapperRecyclerAdapter(adapter); //這里head為什么不會(huì)全屏,因?yàn)長(zhǎng)ayoutInflater需要parent才會(huì)全屏 wrapperRecyclerAdapter.addHeadView(LayoutInflater.from(this).inflate(R.layout.layout_header_view, recyclerView, false)); wrapperRecyclerAdapter.addFootView(new Button(this)); recyclerView.setAdapter(wrapperRecyclerAdapter); // 面向?qū)ο蟮牧蠡驹瓌t,好像不符合最小知道原則,每次調(diào)用需要去new WrapperRecyclerAdapter這樣的一個(gè)包裝者,這肯定是不對(duì)的,所以需要封裝自己的recycleview }
看一下運(yùn)行效果
代碼實(shí)現(xiàn)2
這里我們發(fā)現(xiàn)一個(gè)問(wèn)題,這樣豈不是讓開發(fā)者,每每次去使用的時(shí)候,new原始的adapter,還需要去new WrapperRecyclerAdapter,然后才能給recyclerView去setAdapter,面向?qū)ο蟮牧蠡驹瓌t,好像不符合最小知道原則,每次調(diào)用需要去new WrapperRecyclerAdapter這樣的一個(gè)包裝者,這肯定是不對(duì)的,所以需要封裝自己的recycleview。
所以我們做如下優(yōu)化,將WrapperRecyclerAdapter的new操作,我們可以放入recyclerView中,這樣外界開發(fā)者只需要去關(guān)心WrapperRecycleView和RecyclerView.Adapter就可以了,對(duì)于開發(fā)者來(lái)講,只需關(guān)心RecyclerView自定義就可以了。
自定義WrapperRecycleView
自定義WrapperRecycleView
,重寫方法setAdapter,用于封裝new WrapperRecyclerAdapter的操作
package com.itbird.design.decorator.recycleview; import android.content.Context; import android.util.AttributeSet; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; /** * 自定義WrapperRecycleView,重寫方法setAdapter,用于封裝new WrapperRecyclerAdapter的操作 * Created by itbird on 2022/6/10 */ public class WrapperRecycleView extends RecyclerView { WrapperRecyclerAdapter wrapperRecyclerAdapter; public WrapperRecycleView(@NonNull Context context) { super(context); } public WrapperRecycleView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public WrapperRecycleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void setAdapter(@Nullable Adapter adapter) { wrapperRecyclerAdapter = new WrapperRecyclerAdapter(adapter); super.setAdapter(wrapperRecyclerAdapter); } @Nullable @Override public Adapter getAdapter() { return wrapperRecyclerAdapter; } public void addHeadView(View view) { wrapperRecyclerAdapter.addHeadView(view); } public void addFootView(View view) { wrapperRecyclerAdapter.addFootView(view); } public void removeHeadView(View view) { wrapperRecyclerAdapter.removeHeadView(view); } public void removeFootView(View view) { wrapperRecyclerAdapter.removeFootView(view); } }
調(diào)用一下
/** * 將wrapperadapter的new操作,內(nèi)部實(shí)現(xiàn) v3 * 封裝的必要性,這樣的話,只需要關(guān)注WrapperRecycleView,不再需要關(guān)注WrapperRecyclerAdapter */ public void buttonv3(View view) { findViewById(R.id.wrapperR).setVisibility(View.VISIBLE); findViewById(R.id.recycleview).setVisibility(View.GONE); WrapperRecycleView wrapperRecycleView = findViewById(R.id.wrapperR); wrapperRecycleView.setLayoutManager(new LinearLayoutManager(this)); wrapperRecycleView.setAdapter(adapter); wrapperRecycleView.addHeadView(LayoutInflater.from(this).inflate(R.layout.layout_header_view, wrapperRecycleView, false)); wrapperRecycleView.addFootView(new Button(this)); //這時(shí)再去考慮一個(gè)事情,我們通過(guò)裝飾者模式把a(bǔ)dapter封裝了一層,如果adpater有數(shù)據(jù)更新,導(dǎo)致變動(dòng),這時(shí)會(huì)有問(wèn)題嗎? //這時(shí)會(huì)發(fā)現(xiàn),并未更新,原因是裝飾類,并未做事件響應(yīng) }
以上就是Android開發(fā)可添加頭尾的RecycleView的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Android RecycleView添加頭尾的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android實(shí)現(xiàn)指定時(shí)間定時(shí)觸發(fā)方法
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)指定時(shí)間定時(shí)觸發(fā)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05Android文件存儲(chǔ)SharedPreferences源碼解析
SharedPreferences是安卓平臺(tái)上一個(gè)輕量級(jí)的存儲(chǔ)類,用來(lái)保存應(yīng)用的一些常用配置,比如Activity狀態(tài),Activity暫停時(shí),將此activity的狀態(tài)保存到SharedPereferences中;當(dāng)Activity重載,系統(tǒng)回調(diào)方法onSaveInstanceState時(shí),再?gòu)腟haredPreferences中將值取出2022-08-08Android開發(fā)之ListView的簡(jiǎn)單用法及定制ListView界面操作示例
這篇文章主要介紹了Android開發(fā)之ListView的簡(jiǎn)單用法及定制ListView界面操作,結(jié)合實(shí)例形式分析了Android ListView界面布局相關(guān)操作技巧,需要的朋友可以參考下2019-04-04Android實(shí)現(xiàn)將View保存成Bitmap的方法
這篇文章主要介紹了Android實(shí)現(xiàn)將View保存成Bitmap的方法,涉及Android畫布Canvas、位圖bitmap及View的相關(guān)使用技巧,需要的朋友可以參考下2016-06-06Kotlin by lazy關(guān)鍵字深入探究實(shí)現(xiàn)原理
這篇文章主要介紹了by lazy,在kotlin中使用是很常見的,用于實(shí)現(xiàn)懶加載某個(gè)數(shù)據(jù)。而這兩個(gè)單詞不是一體的,其中by是kotlin中的關(guān)鍵字,用于實(shí)現(xiàn)委托;lazy是一個(gè)方法,他的返回值是委托的具體對(duì)象2022-11-11Android筆記之:App自動(dòng)化之使用Ant編譯項(xiàng)目多渠道打包的使用詳解
本篇文章介紹了,Android筆記之:App自動(dòng)化之使用Ant編譯項(xiàng)目多渠道打包的使用詳解。需要的朋友參考下2013-04-04Android編程雙重單選對(duì)話框布局實(shí)現(xiàn)與事件監(jiān)聽方法示例
這篇文章主要介紹了Android編程雙重單選對(duì)話框布局實(shí)現(xiàn)與事件監(jiān)聽方法,涉及Android雙重單選對(duì)話框的界面布局與事件監(jiān)聽、響應(yīng)等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10android多線程斷點(diǎn)下載-帶進(jìn)度條和百分比進(jìn)度顯示效果
下面小編就為大家?guī)?lái)一篇android多線程斷點(diǎn)下載-帶進(jìn)度條和百分比進(jìn)度顯示效果。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Android調(diào)節(jié)屏幕亮度實(shí)現(xiàn)代碼
這篇文章主要介紹了Android調(diào)節(jié)屏幕亮度實(shí)現(xiàn)代碼,調(diào)節(jié)屏幕亮度時(shí),先設(shè)置當(dāng)前activity亮度,再并保存為系統(tǒng)亮度即可,本文分別給出兩個(gè)步驟的實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-05-05