Android使用BaseSectionQuickAdapter动态生成不规则宫格

本文介绍了如何在Android应用中实现一个自定义的宫格布局,该布局可以根据不同场景动态调整列数。通过使用BaseQuickAdapter库,简化了Adapter的实现,并给出了具体的代码实现和示例。此外,文章还展示了如何计算和分配每列的占比,以适应1-6列的宫格布局。

学更好的别人,

做更好的自己。

——《微卡智享》

本文长度为3249,预计阅读6分钟

前言

最近做的新产品设备到了产品摆放的显示,由于客户不同,产品本身的宫格定义也不相同,为了不用每个项目重新改一遍布局,于是就做了个自定义的宫格布局,下面是演示Demo,产品里面还会有别的优化。

实现效果

从上图的红框标的处就是我们自定义的宫格列表,443|4444总长度代表的一共有多少行,中间的|是分格线,标识作用,每个数字代表着每行中的列数,所以443|4444,代表一共有7行,其中1行为4列,2行为4列,3行为3列,分隔线,4行为4列,5行为4列,6行为4列,7行为4列。

代码实现

微卡智享

实现这个效果采用的是BaseSectionQuickAdapter,做为Android的开发者,相信BaseRecyclerViewAdapter应该很多人都在用,这是一个强大而灵活的RecyclerView Adapter,以前一直用原生的Adapter,然后最近项目中使用了PagedListAdapter,效果并是不太理想,所以后来又改用的BaseQuickAdapter,只能说真香。

简单使用方法

builld.gradle中加入

    repositories {
        maven { url 'https://jitpack.io' }
    }

dependencies {
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34'
}

最新的版本是3.0.4了,作者用Kotlin重构了些,还解决了一些BUG,不过我在刚用的时候还没研究明白3.0.4的使用,创建的有问题,所以改为了2.9.34

01

定义Bean

一共两个类,一个药品简单信息的,一个设备和对应的格数显示的,其中药品类CDrugs为设备类CDevice的子类,所以在CDevice类中需要继承SectionEntity

package dem.vaccae.basequickadapterdemo.bean


/**
 * 作者:Vaccae
 * 邮箱:3657447@qq.com
 * 创建时间:12:30
 * 功能模块说明:
 */
class CDrugs {


    var colspansize = 15
    var drugs_code = ""
    var drugs_name = ""
    var drugs_specs = ""
    var qty_h = 50
    var qty_l = 20


}
package dem.vaccae.basequickadapterdemo.bean


import com.chad.library.adapter.base.entity.SectionEntity


/**
 * 作者:Vaccae
 * 邮箱:3657447@qq.com
 * 创建时间:12:33
 * 功能模块说明:
 */
class CDevice : SectionEntity<CDrugs> {


    constructor(isHead: Boolean, headstr:String):super(isHead, headstr)


    constructor(item: CDrugs):super(item)


    var dev_seri = 1;


    var dev_gridstr = "555|5555"


    var dev_split = false


}

划重点:

药品类中有一个colspansize的字段,这个是用来设置当前格的占比,其实从图中可以看到,实现宫格来说,一般一行不会超过6个了,所以为了每行不同的格数能够平均显示,能适配1-6都没有问题的,就要求出1-6的最小公倍数,其中2,3,5都是质数,所以2X3X5=30,而30又不能被4整除,4又是2的倍数,所以30再X2即得到60了,并且6也可以被整除。

所以来说设置一个常量60就是每行宫格的固定数,然后能过计算每行显示几列,来求出每列的占比处理即可。

02

SectionQuickAdapter

package dem.vaccae.basequickadapterdemo


import com.chad.library.adapter.base.BaseSectionQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.chad.library.adapter.base.entity.SectionEntity
import dem.vaccae.basequickadapterdemo.bean.CDevice
import dem.vaccae.basequickadapterdemo.bean.CDrugs


/**
 * 作者:Vaccae
 * 邮箱:3657447@qq.com
 * 创建时间:12:37
 * 功能模块说明:
 */
class SectionQuickAdapter(layoutResId: Int, pHeadResId: Int, data: MutableList<CDevice>?) :
    BaseSectionQuickAdapter<CDevice, BaseViewHolder>(layoutResId, pHeadResId, data) {




    override fun convert(helper: BaseViewHolder?, item: CDevice?) {
        helper?.let {
            item?.let {
                dev->
                var drugs = dev.t
                it.setText(R.id.tv_drugcode, drugs.drugs_code)
                    .setText(R.id.tv_drugname, drugs.drugs_name)
                    .setText(R.id.tvqty_h, drugs.qty_h.toString())
                    .setText(R.id.tv_qtyl, drugs.qty_l.toString())
            }


        }
    }


    override fun convertHead(helper: BaseViewHolder?, item: CDevice?) {
        helper?.let {
            item?.let { dev ->
                it.setText(R.id.tv_serialno, dev.dev_seri.toString())
                it.setText(R.id.tv_gridstr, dev.dev_gridstr)
                if (item.dev_split) {
                    it.setVisible(R.id.tv_serialno, false)
                } else {
                    it.setVisible(R.id.tv_serialno, true)
                }
            }
        }
    }


}

SectionQuickAdapter设置非常简单,就是是Header时显示什么,不是Header时显示什么,使用BaseQuickAdapter真香的原因就是Adapter里面的代码确实少了很多,用起来方便的很。

03

MainActivity

MainActivity中没有什么特别的,最主要的就是计算生成列表。列表计算时主核心的就是怎么根据字符串进行数据处理。

    fun getGridList(str: String): ArrayList<Int> {
        val list = ArrayList<Int>()
        for (s in str) {
            if (s.toString() == "|") {
                list.add(-1)
            } else {
                list.add(s.toString().toInt())
            }
        }
        return list
    }

getGridList是将传入的字符串转成List<int>的列表,如果是|则设置为-1,代表着是分隔符。

使用for(s in str)遍历String时,每个一s都是char类型了,直接toint得到的数字是Ascii码的数字,所以需要先toString后再toInt。

    fun initData() {
        devices = ArrayList()
        for (i in 1..3) {
            var dev = CDevice(true, i.toString())
            dev.dev_seri = i
            var idx = i % gridstrtype.size
            dev.dev_gridstr = gridstrtype[idx]


            devices.add(dev)


            var list = getGridList(dev.dev_gridstr)
            var rowno = 1;
            for (k in list) {
                if (k > 0) {
                    var spansize = colspan / k
                    for (itemi in 1..k) {
                        var drugs = CDrugs()
                        drugs.drugs_code =
                            i.toString() + rowno.toString() + String.format("%04d", itemi)
                        var drugsidx = itemi % drugnames.size
                        drugs.drugs_name = drugnames[drugsidx]
                        drugs.qty_h = 50
                        drugs.qty_l = 20
                        drugs.colspansize = spansize


                        devices.add(CDevice(drugs))
                    }
                    rowno++
                } else {
                    var dev = CDevice(true, i.toString())
                    dev.dev_seri = i
                    dev.dev_gridstr = "---------------------------------------"
                    dev.dev_split = true;
                    devices.add(dev)
                }
            }
        }
    }

初始化数据时就通过getGridList得到集合后,当前列数大于0时,通过设置的最小公倍数60除当前列数得到的占比。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        initData()


        sadapter = SectionQuickAdapter(R.layout.rcl_body, R.layout.rcl_head, devices)
        val gridLayoutManager = GridLayoutManager(this, colspan)
        recyclerview.layoutManager = gridLayoutManager
        recyclerview.adapter = sadapter


        gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                var item = devices.get(position)
                if (item.isHeader) {
                    return colspan
                } else {
                    var drugs = item.t
                    return drugs.colspansize
                }
            }
        }








    }

最后创建GridLayoutManager,每行的格数为60,然后在spanSizeLookup中的getSpanSize中做处理,当是Header时占满60格,如果不是Header时,设置为当到前对象的colspansize即可。

源码地址

https://github.com/Vaccae/AndroidBaseQuickAdapterDemo.git

扫描二维码

获取更多精彩

微卡智享

「 往期文章 」

Android之任务调度WorkManager和JobSchedule的使用

Android使用LiveEventBus消息实现组件间通讯

Android制作AAR包并混淆后加载调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vaccae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值