设计思想培养:装饰者模式下的RecyclerView添加头、尾

前言

一个高复用、低耦合的代码不会让你在第一次去实现代码的时候感到舒服
但是他会在你后面做扩展、和同类需求的时候,直呼真香!!!

最近写需求,借用到装饰者思想做了RecyclerView的头和尾的扩展
感觉很不错,赶紧拿出来说一说,嘻嘻

ps:本篇文章只是帮助大家,在实现需求的过程中也能潜移默化的使用设计模式来优化代码

Android中的装饰者

首先一句话总结装饰者:就是不通过继承的方式,来扩展某个对象的功能,达到我们想要实现的效果。
举两个小例子,不细说,因为前面已经讲过装饰者模式相关的内容

  • InputStream装饰者

InputStream装饰者:在Android中,我们经常需要读取文件或者网络流。InputStream是用于读取字节流的抽象类,而Android提供了许多装饰者类来扩展InputStream的功能。
例如,BufferedInputStream和DataInputStream都是InputStream的装饰者类,它们添加了缓冲和数据类型转换的功能。

FileInputStream fileInputStream = new FileInputStream("example.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
  • View装饰者

Android中的UI组件都继承自View类,而Android提供了装饰者类来扩展View的功能
例如,可以使用LayoutInflater来给布局文件添加一些额外的装饰

LayoutInflater inflater = LayoutInflater.from(context);
View originalView = inflater.inflate(R.layout.original_layout, parentLayout, false);
ViewDecorator viewDecorator = new ViewDecorator(originalView);
View decoratedView = viewDecorator.decorate();
parentLayout.addView(decoratedView);

基于这种思想,在做RecyclerView的头和尾的扩展想到了,利用这种装饰者扩展的方式去加头和尾,而保留中间数据层的原有属性。

代码实现

利用DecorateAdapter去装饰RecyclerView.Adapter,从而扩展HeadView、FooterView
在这里插入图片描述
中间内容我们使用contentAdapter来表示,假设就是简单的Item结构,就不做代码介绍了。

第一步:创建装饰器DecorateAdapter

创建装饰器DecorateAdapter并实现增加头部和尾部Item的相关方法、和成员变量
并将contentAdapter作为原始的内容列表

class DecorateAdapter(
    val contentAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IdecorateList {

    /**save head View*/
    private val headerList: MutableList<View> by lazy {
        mutableListOf()
    }

    /**save footer view*/
    private val footerList: MutableList<View> by lazy {
        mutableListOf()
    }

    /**常规方法*/
    ......
    ......

    override fun getItemCount(): Int {
        //记得加上contentAdapter的Item条目
        return contentAdapter.itemCount + headerList.size + footerList.size
    }

    override fun addHeaderView(header: View) {
        if (!headerList.contains(header)) {
            headerList.add(header)
            refreshList()
        }
    }

    override fun removeHeaderView(header: View) {
        if (headerList.contains(header)) {
            headerList.remove(header)
            refreshList()
        }
    }

    override fun addFooterView(foot: View) {
        if (!footerList.contains(foot)) {
            footerList.add(foot)
            refreshList()
        }
    }

    override fun removeFooterView(foot: View) {
        if (footerList.contains(foot)) {
            footerList.remove(foot)
            refreshList()
        }
    }

    override fun refreshList() {
        notifyDataSetChanged()
    }
}

第二步:处理头部、中间内容、尾部的绑定关系

  • 处理头部、中间、尾部的不同绑定的视图:也就是createHeaderViewHolder处理
/**创建头部的ViewHolder*/
private fun createHeaderViewHolder(view: View): RecyclerView.ViewHolder {
    return HeaderViewHolder(view)
}

/**创建尾部的ViewHolder*/
private fun createFooterViewHolder(view: View): RecyclerView.ViewHolder {
    return FooterViewHolder(view)
}

override fun onCreateViewHolder(parent: ViewGroup, position: Int): RecyclerView.ViewHolder {

    /**头部样式展示*/
    if (headerList.isNotEmpty() && position in 0 until headerList.size) {
        return createHeaderViewHolder(headerList[position])
    }

    /**中间内容展示*/
    val startPosition = if (headerList.isNotEmpty()) headerList.size else 0
    val endPosition =
        if (headerList.isNotEmpty()) headerList.size + contentAdapter.itemCount else contentAdapter.itemCount
    if (position in startPosition until endPosition) {
        return contentAdapter.onCreateViewHolder(parent, position)
    }

    /**尾部样式展示*/
    return createFooterViewHolder(footerList[position - endPosition]) /**注意这里的取值*/
}
  • 处理处理头部、中间、尾部的数据绑定:也就是onBindViewHolder的处理
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

    if (headerList.isNotEmpty() && position in 0 until headerList.size) {
        return
    }
    /**中间的内容数据绑定*/
    val startPosition = if (headerList.isNotEmpty()) headerList.size else 0
    val endPosition =
        if (headerList.isNotEmpty()) headerList.size + contentAdapter!!.itemCount else contentAdapter!!.itemCount
    if (position in startPosition until endPosition) {
        /**注意计算的时候,要减去HeadView*/
        contentAdapter?.onBindViewHolder(holder, position - headerList.size)
    }
}

第三步:装饰器的使用

把内容区域的ContentAdapter,通过DecorateAdapter进行包装,之后调用包装后的decorateAdapter进行添加HeadView

decorate = findViewById(R.id.rv_decorate)
val decorateAdapter = DecorateAdapter(ContentAdapter())
decorate.adapter = decorateAdapter
decorate.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)

decorateAdapter.addHeaderView(
    LayoutInflater.from(this).inflate(R.layout.layout_header, decorate, false)
)

第四步:改进、直接封装一个View出来

把装饰者封在内部
毕竟我们在调用的时候,还是想当一个View直接拿来用,改进一下

class decorateRecyclerView : RecyclerView {

    private var DecorateAdapter: DecorateAdapter? = null

    @JvmOverloads
    constructor(context: Context, attributes: AttributeSet? = null) : super(context, attributes)

    override fun setAdapter(adapter: Adapter<ViewHolder>?) {
        DecorateAdapter = DecorateAdapter(adapter!!)
        super.setAdapter(DecorateAdapter)
    }

    fun addHeaderView(header: View) {
        DecorateAdapter?.addHeaderView(header)
    }

    fun removeHeaderView(header: View) {
        DecorateAdapter?.removeHeaderView(header)
    }

    fun addFooterView(foot: View) {
        DecorateAdapter?.addFooterView(foot)
    }

    fun removeFooterView(foot: View) {
        DecorateAdapter?.removeFooterView(foot)
    }
}

调用 & 使用

decorate = findViewById(R.id.rv_decorate)
decorate.adapter = ContentAdapter()
decorate.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)

decorate.addHeaderView(
    LayoutInflater.from(this).inflate(R.layout.layout_header, decorate, false)
)
decorate.addFooterView(
    LayoutInflater.from(this).inflate(R.layout.layout_footer, decorate, false)
)

总结

本篇呢,只是想说一下如何去潜移默化的使用设计模式去改变我们的代码。
举了一个扩展RecyclerView头和尾的例子。
如果不用设计模式的话,我想你的头和尾的处理逻辑都是需要冗余在ContentAdapter中的
问题:
1、那么你的ContentAdapter的定义界限是什么?整个页面的业务?那难免太难维护了
2、如果只需要服用ContentAdapter怎么处理?粘贴复制,多造一个类出来?

而通过上面我们介绍的装饰者模式就能解决这两个:复用、耦合的问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值