目录
- 正文
- 设计UML图
- 代码实现1
- WrapperRecyclerAdapter
- 代码实现2
- 自定义WrapperRecycleView
正文
界面编码设计实现中,我们肯定会用到列表展示控件,大家肯定用过ListView。后来google推出了RecycleView,帮我们去做了很多优化(内置viewholder增加复用率、可以支持局部刷新、布局可以通过外层指定layout等),正常的使用,如下:
MyRecycleViewAdapter adapter; | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_decorator); | |
Component component = new ConCreateComponent(); | |
ComponentImplA impl = new ComponentImplA(component); | |
impl.operation(); | |
List<String> list = new ArrayList<>(); | |
for (int i =; i < 100; i++) { | |
list.add("position " + i); | |
} | |
adapter = new MyRecycleViewAdapter(this); | |
adapter.setData(list); | |
} | |
/** | |
* 原始的yRecycleViewAdapter v | |
*/ | |
public void buttonv(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大家发现有一个问题,我们如果想要为这个RecycleView添加自定义的头部view、尾部view的话,官方这个明显做不到,那这时我们可以考虑用装饰者模式或者继承去扩展一下。
设计UML图
首先我们通过UML图,来设计一下,设计之前想一下,我们是想要扩展RecyclerView.Adapter和RecyclerView,从而可以实现addHeadView、addFootView的功能,那么需要以下几步骤。
1)首先,由于RecyclerView.Adapter已经是一个抽象类接口,我们自己继承与它,然后进行包装定义为WrapperRecyclerAdapter类
2)WrapperRecyclerAdapter肯定要持有RecyclerView.Adapter的引用,所以需要有一个构造方法,将RecyclerView.Adapter的引用传递进来
3)由于WrapperRecyclerAdapter继承与RecyclerView.Adapter,肯定要去实现关键的方法,onCreateViewHolder(创建viewitem的holder)、onBindViewHolder(viewholder数据绑定)、getItemCount(获取列表item的数量)
4)关键的一步来了,就是使用RecyclerView.Adapter、footviews、headviews,这三者组合,重写上面的三个重要方法,给列表相应位置创建对应的item
代码实现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包装类,扩展实现headView、footView的添加 | |
* Created by itbird on/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() { | |
public void onChanged() { | |
notifyDataSetChanged(); | |
} | |
}); | |
} | |
public RecyclerView.ViewHolder onCreateViewHolder(int position) { ViewGroup parent, | |
//头部的,返回头部的viewholder | |
if (position < headViews.size()) { | |
return new WrapperViewHolder(headViews.get(position)); | |
} | |
//adapter返回中间数据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())); | |
} | |
public void onBindViewHolder(int position) { RecyclerView.ViewHolder holder, | |
if (position < headViews.size() || position >= adapter.getItemCount() + headViews.size()) { | |
return; | |
} | |
//头部和底部不需要做处理,只需要真实的adapter需要处理 | |
adapter.onBindViewHolder(holder, position - headViews.size()); | |
} | |
public int getItemViewType(int position) { | |
return position; | |
} | |
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( { View itemView) | |
super(itemView); | |
} | |
} | |
} |
这时再去调用,发现就可以如下调用
/** | |
* 扩展的,可以增加头尾的recycleview v | |
*/ | |
public void buttonv(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 | |
} |
看一下运行效果
代码实现2
这里我们发现一个问题,这样岂不是让开发者,每每次去使用的时候,new原始的adapter,还需要去new WrapperRecyclerAdapter,然后才能给recyclerView去setAdapter,面向对象的六大基本原则,好像不符合最小知道原则,每次调用需要去new WrapperRecyclerAdapter这样的一个包装者,这肯定是不对的,所以需要封装自己的recycleview。
所以我们做如下优化,将WrapperRecyclerAdapter的new操作,我们可以放入recyclerView中,这样外界开发者只需要去关心WrapperRecycleView和RecyclerView.Adapter就可以了,对于开发者来讲,只需关心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/6/10 | |
*/ | |
public class WrapperRecycleView extends RecyclerView { | |
WrapperRecyclerAdapter wrapperRecyclerAdapter; | |
public WrapperRecycleView( { Context context) | |
super(context); | |
} | |
public WrapperRecycleView( { Context context, AttributeSet attrs) | |
super(context, attrs); | |
} | |
public WrapperRecycleView(int defStyleAttr) { Context context, AttributeSet attrs, | |
super(context, attrs, defStyleAttr); | |
} | |
public void setAdapter( { Adapter adapter) | |
wrapperRecyclerAdapter = new WrapperRecyclerAdapter(adapter); | |
super.setAdapter(wrapperRecyclerAdapter); | |
} | |
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操作,内部实现 v | |
* 封装的必要性,这样的话,只需要关注WrapperRecycleView,不再需要关注WrapperRecyclerAdapter | |
*/ | |
public void buttonv(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有数据更新,导致变动,这时会有问题吗? | |
//这时会发现,并未更新,原因是装饰类,并未做事件响应 | |
} |