Android開發(fā)可添加頭尾的RecycleView的實現(xiàn)
正文
界面編碼設計實現(xiàn)中,我們肯定會用到列表展示控件,大家肯定用過ListView。后來google推出了RecycleView,幫我們去做了很多優(yōu)化(內置viewholder增加復用率、可以支持局部刷新、布局可以通過外層指定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)有一個問題,我們如果想要為這個RecycleView添加自定義的頭部view、尾部view的話,官方這個明顯做不到,那這時我們可以考慮用裝飾者模式或者繼承去擴展一下。
設計UML圖
首先我們通過UML圖,來設計一下,設計之前想一下,我們是想要擴展RecyclerView.Adapter和RecyclerView,從而可以實現(xiàn)addHeadView、addFootView的功能,那么需要以下幾步驟。
1)首先,由于RecyclerView.Adapter已經是一個抽象類接口,我們自己繼承與它,然后進行包裝定義為WrapperRecyclerAdapter類
2)WrapperRecyclerAdapter肯定要持有RecyclerView.Adapter的引用,所以需要有一個構造方法,將RecyclerView.Adapter的引用傳遞進來
3)由于WrapperRecyclerAdapter繼承與RecyclerView.Adapter,肯定要去實現(xiàn)關鍵的方法,onCreateViewHolder(創(chuàng)建viewitem的holder)、onBindViewHolder(viewholder數(shù)據(jù)綁定)、getItemCount(獲取列表item的數(shù)量)
4)關鍵的一步來了,就是使用RecyclerView.Adapter、footviews、headviews,這三者組合,重寫上面的三個重要方法,給列表相應位置創(chuàng)建對應的item

代碼實現(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包裝類,擴展實現(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;
}
//頭部和底部不需要做處理,只需要真實的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);
}
}
}
這時再去調用,發(fā)現(xiàn)就可以如下調用
/**
* 擴展的,可以增加頭尾的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為什么不會全屏,因為LayoutInflater需要parent才會全屏
wrapperRecyclerAdapter.addHeadView(LayoutInflater.from(this).inflate(R.layout.layout_header_view, recyclerView, false));
wrapperRecyclerAdapter.addFootView(new Button(this));
recyclerView.setAdapter(wrapperRecyclerAdapter);
// 面向對象的六大基本原則,好像不符合最小知道原則,每次調用需要去new WrapperRecyclerAdapter這樣的一個包裝者,這肯定是不對的,所以需要封裝自己的recycleview
}
看一下運行效果

代碼實現(xiàn)2
這里我們發(fā)現(xiàn)一個問題,這樣豈不是讓開發(fā)者,每每次去使用的時候,new原始的adapter,還需要去new WrapperRecyclerAdapter,然后才能給recyclerView去setAdapter,面向對象的六大基本原則,好像不符合最小知道原則,每次調用需要去new WrapperRecyclerAdapter這樣的一個包裝者,這肯定是不對的,所以需要封裝自己的recycleview。
所以我們做如下優(yōu)化,將WrapperRecyclerAdapter的new操作,我們可以放入recyclerView中,這樣外界開發(fā)者只需要去關心WrapperRecycleView和RecyclerView.Adapter就可以了,對于開發(fā)者來講,只需關心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);
}
}
調用一下
/**
* 將wrapperadapter的new操作,內部實現(xiàn) v3
* 封裝的必要性,這樣的話,只需要關注WrapperRecycleView,不再需要關注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));
//這時再去考慮一個事情,我們通過裝飾者模式把adapter封裝了一層,如果adpater有數(shù)據(jù)更新,導致變動,這時會有問題嗎?
//這時會發(fā)現(xiàn),并未更新,原因是裝飾類,并未做事件響應
}以上就是Android開發(fā)可添加頭尾的RecycleView的實現(xiàn)的詳細內容,更多關于Android RecycleView添加頭尾的資料請關注腳本之家其它相關文章!
相關文章
Android文件存儲SharedPreferences源碼解析
SharedPreferences是安卓平臺上一個輕量級的存儲類,用來保存應用的一些常用配置,比如Activity狀態(tài),Activity暫停時,將此activity的狀態(tài)保存到SharedPereferences中;當Activity重載,系統(tǒng)回調方法onSaveInstanceState時,再從SharedPreferences中將值取出2022-08-08
Android開發(fā)之ListView的簡單用法及定制ListView界面操作示例
這篇文章主要介紹了Android開發(fā)之ListView的簡單用法及定制ListView界面操作,結合實例形式分析了Android ListView界面布局相關操作技巧,需要的朋友可以參考下2019-04-04
Android實現(xiàn)將View保存成Bitmap的方法
這篇文章主要介紹了Android實現(xiàn)將View保存成Bitmap的方法,涉及Android畫布Canvas、位圖bitmap及View的相關使用技巧,需要的朋友可以參考下2016-06-06
Kotlin by lazy關鍵字深入探究實現(xiàn)原理
這篇文章主要介紹了by lazy,在kotlin中使用是很常見的,用于實現(xiàn)懶加載某個數(shù)據(jù)。而這兩個單詞不是一體的,其中by是kotlin中的關鍵字,用于實現(xiàn)委托;lazy是一個方法,他的返回值是委托的具體對象2022-11-11
Android筆記之:App自動化之使用Ant編譯項目多渠道打包的使用詳解
本篇文章介紹了,Android筆記之:App自動化之使用Ant編譯項目多渠道打包的使用詳解。需要的朋友參考下2013-04-04
Android編程雙重單選對話框布局實現(xiàn)與事件監(jiān)聽方法示例
這篇文章主要介紹了Android編程雙重單選對話框布局實現(xiàn)與事件監(jiān)聽方法,涉及Android雙重單選對話框的界面布局與事件監(jiān)聽、響應等相關操作技巧,需要的朋友可以參考下2017-10-10

