Jetpack Compose for Desktop实现复杂的自动布局网格

1,595 阅读1分钟

效果如下:

GIF 2021-04-20 21-25-11.gif

主要实现随窗口尺寸自动调整元素位置的功能,由于实际上考虑了window的尺寸(实现过程并未涉及window),在android上并不适用(虽然正常运行应该没有问题)。实现这种动态控件,思路还是很清晰的,就是用BoxWithConstraints测量待绘图区域的尺寸,根据得到的尺寸画出相应的控件。

代码如下:

import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlin.math.floor


class TestUI2 {

    /**
     * 测试用数据
     */
    data class TestData(
        val id: Int,
        val name: String,
        val category: String,
        val state: String,
    )

    @Composable
    fun GridView(dataList:MutableList<TestData>) {
        //对数据按类别和id排序
        dataList.sortWith(compareBy({it.category},{it.id}))
        /**
         * 区间宽度,随窗口尺寸变化更新
         */
        var districtWidth by remember { mutableStateOf(0f) }
        /**
         * 每个方框的尺寸
         */
        val gridBoxWidth:Float=200f
        /**
         * 每列方框的数量
         */
        var everyRowBoxQuantity:Int
        Column (
            modifier = Modifier
                //可滚动
                .verticalScroll(rememberScrollState())
        ){
            BoxWithConstraints {
                //获取Column最大宽度
                districtWidth=maxWidth.value
                //计算每列方框的数量
                everyRowBoxQuantity=floor(districtWidth/gridBoxWidth).toInt()
                //类别表
                val categoryList:MutableList<String> = mutableListOf()
                //显示列表,类别-数据列表
                val gridList:MutableMap<String,List<TestData>> = mutableMapOf()
                dataList.groupBy { it.category }.forEach { t, u ->
                    categoryList.add(t)
                    gridList.put(t,u)
                }
                Column {
                    for(i in gridList){
                        Text("种类"+i.key)
                        GridRow(everyRowBoxQuantity,i.value)
                    }
                }
            }
        }
    }

    @Composable
    fun GridRow(everyRowBoxQuantity:Int,rowList:List<TestData>){
        var boxQuantity=everyRowBoxQuantity-1
        //至少显示一行
        if(boxQuantity<=0)boxQuantity=1
        //分配每行box时计数
        var i=1
        //每行显示的内容
        val everyRowList:MutableList<TestData> = mutableListOf()
        for(it in rowList){
            everyRowList.add(it)
            //每行分配完成或最后一个元素时,显示Row
            if(i%boxQuantity==0||it==rowList.last())
            {
                Row {
                    everyRowList.forEach {
                        GridBox(it)
                    }
                }
                everyRowList.clear()
            }
            i++
        }
    }

    @Composable
    fun GridBox(testData: TestData) {
        var u:Color=Color.Black
        //不同的状态显示不同的值
        when(testData.state){
            "0"->u= Color.Black
            "1"->u= Color.Blue
            "2"->u= Color.Green
        }
        Box(
            modifier = Modifier
                .padding(16.dp)
                .width(200.dp)
                .height(130.dp)
                .background(u)
        ){
            Column {
                Text(testData.id.toString())
                Text(testData.name)
            }
        }
    }
}