当前位置: 首页 > news >正文

Compose笔记(二十七)--网格布局

        这一节主要了解一下Compose中的网格布局,这种布局在开发中相对比较常见,现简单总结如下:

API
1. LazyVerticalGrid
功能:创建垂直滚动的懒加载网格,仅在元素进入可视区域时才会渲染。
核心参数:
columns:指定列数,支持两种模式:
GridCells.Fixed(n):固定n列。
GridCells.Adaptive(minSize):自适应列宽,确保每列至少有minSize宽度。
contentPadding:内边距。
verticalArrangement/horizontalArrangement:元素间距和排列方式。
适用场景:大多数网格布局场景。
2. LazyHorizontalGrid
功能:创建水平滚动的懒加载网格。
核心参数:
rows:指定行数(类似LazyVerticalGrid的columns)。
其他参数与LazyVerticalGrid类似。
适用场景:横向滚动的网格(如水平标签页、横向商品推荐)。
3. GridCells(枚举类)
作用:配合LazyVerticalGrid/LazyHorizontalGrid指定网格的列数/行数。
两个值:
Fixed(count):固定列数 / 行数。
Adaptive(minSize):自适应模式,根据最小尺寸自动计算列数 / 行数。
4. FlowRow 
modifier:应用于整个FlowRow的修饰符(如设置尺寸、背景、边距等)。
horizontalArrangement:控制每行内子元素的水平排列方式.
verticalArrangement:控制每行之间的垂直排列方式
maxItemsInEachRow:限制每行最多显示的元素数量。
overflow: 当内容超出最大行数时的处理策略。
content: 定义 FlowRow 的子元素。

栗子:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material.Card@Composable
fun FixedGridExample() {val items = List(6) { "Item $it" }LazyVerticalGrid(columns = GridCells.Fixed(3), // 固定3列contentPadding = PaddingValues(20.dp),verticalArrangement = Arrangement.spacedBy(4.dp),horizontalArrangement = Arrangement.spacedBy(12.dp)) {items(items) { item ->Card(onClick = {},modifier = Modifier.height(100.dp)) {Box(contentAlignment = Alignment.Center,modifier = Modifier.fillMaxSize()) {Text(item)}}}}
}@Composable
fun AdaptiveGridExample() {val items = List(15) { "Item $it" }LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 120.dp), // 自适应列宽contentPadding = PaddingValues(16.dp),verticalArrangement = Arrangement.spacedBy(8.dp),horizontalArrangement = Arrangement.spacedBy(8.dp)) {items(items) { item ->Card(onClick = {},modifier = Modifier.height(100.dp)) {Box(contentAlignment = Alignment.Center,modifier = Modifier.fillMaxSize()) {Text(item, color = Color(0xFFFFFFFF))}}}}
}
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlin.math.max@Composable
fun GridExample() {val items = List(20) { "Item $it - " + "a".repeat((5..20).random()) }BoxWithConstraints {val columnWidth = 120.dpval availableWidth = constraints.maxWidth.dpval columnCount = max(1, (availableWidth / columnWidth).toInt())val columns = remember { MutableList(columnCount) { mutableStateListOf<@Composable () -> Unit>() } }// 将items分配到各列LaunchedEffect(items) {columns.forEach { it.clear() }items.forEachIndexed { index, item ->val column = index % columnCountcolumns[column].add {StaggeredItem(item)}}}Row(horizontalArrangement = Arrangement.spacedBy(8.dp),modifier = Modifier.fillMaxWidth().padding(16.dp)) {columns.forEach { columnItems ->Column(verticalArrangement = Arrangement.spacedBy(8.dp),modifier = Modifier.weight(1f)) {columnItems.forEach { item ->item()}}}}}
}@Composable
private fun StaggeredItem(text: String) {Card(modifier = Modifier.heightIn(min = 50.dp)) {Box(contentAlignment = Alignment.Center,modifier = Modifier.fillMaxWidth().padding(8.dp)) {Text(text)}}
}
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp@OptIn(ExperimentalLayoutApi::class)
@Composable
fun FlowLayoutExample1() {val items = listOf("Apple", "Banana", "Cherry", "Date", "Eggplant","Fig", "Grape", "Honeydew", "Kiwi", "Lemon")Column(modifier = Modifier.padding(16.dp)) {Text("FlowLayout示例", style = MaterialTheme.typography.titleMedium)Spacer(modifier = Modifier.height(16.dp))FlowRow(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.spacedBy(10.dp),verticalArrangement = Arrangement.spacedBy(10.dp)) {items.forEach { item ->Card() {Text(text = item,modifier = Modifier.padding(8.dp))}}}}
}
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.*
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp@Composable
fun CustomFlowLayout(modifier: Modifier = Modifier,horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,verticalArrangement: Arrangement.Vertical = Arrangement.Top,horizontalSpacing: Dp = 0.dp,verticalSpacing: Dp = 0.dp,content: @Composable () -> Unit
) {Layout(content = content,modifier = modifier) { measurables, constraints ->// 存储每行的Placeable和高度val rows = mutableListOf<Row>()var currentRow = mutableListOf<Placeable>()var currentRowWidth = 0var currentRowMaxHeight = 0for (measurable in measurables) {val placeable = measurable.measure(constraints.copy(minWidth = 0, minHeight = 0))if (currentRowWidth > 0 && currentRowWidth + placeable.width > constraints.maxWidth) {rows.add(Row(currentRow, currentRowMaxHeight))currentRow = mutableListOf(placeable)currentRowWidth = placeable.widthcurrentRowMaxHeight = placeable.height} else {currentRow.add(placeable)currentRowWidth += placeable.width + horizontalSpacing.roundToPx()currentRowMaxHeight = maxOf(currentRowMaxHeight, placeable.height)}}if (currentRow.isNotEmpty()) {rows.add(Row(currentRow, currentRowMaxHeight))}val height = rows.sumOf { it.height } +verticalSpacing.roundToPx() * (rows.size - 1)layout(constraints.maxWidth, height) {var yPosition = 0rows.forEach { row ->var xPosition = 0val rowWidth = row.placeables.sumOf { it.width } +horizontalSpacing.roundToPx() * (row.placeables.size - 1)val horizontalOffset = when (horizontalArrangement) {Arrangement.Start -> 0Arrangement.End -> constraints.maxWidth - rowWidthArrangement.Center -> (constraints.maxWidth - rowWidth) / 2else -> { 0 }}xPosition += horizontalOffsetrow.placeables.forEach { placeable ->placeable.placeRelative(x = xPosition,y = yPosition + when (verticalArrangement) {Arrangement.Top -> 0Arrangement.Bottom -> row.height - placeable.heightArrangement.Center -> (row.height - placeable.height) / 2else -> { 0 }})xPosition += placeable.width + horizontalSpacing.roundToPx()}yPosition += row.height + verticalSpacing.roundToPx()}}}
}private data class Row(val placeables: List<Placeable>,val height: Int
)@Composable
fun FlowLayoutExample2() {val items = listOf("Short", "A bit longer", "This is a long text", "Medium","Another short one", "Very very very long text here", "Shorty")Column(modifier = Modifier.padding(16.dp)) {Text("自定义FlowLayout", style = MaterialTheme.typography.labelMedium)Spacer(modifier = Modifier.height(16.dp))CustomFlowLayout(horizontalArrangement = Arrangement.Start,verticalArrangement = Arrangement.Center,horizontalSpacing = 8.dp,verticalSpacing = 8.dp,modifier = Modifier.fillMaxWidth()) {items.forEach { item ->Card() {Text(text = item,modifier = Modifier.padding(8.dp))}}}}
}

注意:
1 FlowRow宽度决定换行逻辑,必须有明确的最大宽度才能正确计算换行位置;
2 FlowRow的高度由内容决定,可通过maxLines限制行数;
3 LazyVerticalGrid为动态内容提供唯一键,可以减少不必要的重组;
4 避免在另一个滚动容器(如LazyColumn)中嵌套LazyVerticalGrid,可能导致滚动冲突;

http://www.lqws.cn/news/467407.html

相关文章:

  • SwinTransformer 改进:小波+注意力模块(Wavelet-Guided Attention)
  • 【LeetCode 热题 100】15. 三数之和——排序 + 双指针解法
  • WebeServer实现:学到了哪些东西
  • 缓存与加速技术实践-Kafka消息队列
  • Axios 在 Vue3 项目中的使用:从安装到组件中的使用
  • 【软考高级系统架构论文】论 SOA 在企业集成架构设计中的应用
  • 【软考高级系统架构论文】论多源数据集成及应用
  • AR眼镜与3D建模社区建设
  • stm32串口(uart)2转发到串口(uart)3实现
  • JVM知识点
  • 启动hardhat 项目,下载依赖的npm问题
  • React 虚拟dom
  • GNU Octave 基础教程(8):GNU Octave 常用数学函数
  • git的命令
  • IEC61850 通信协议测试验证方法详解
  • 经典:在浏览器地址栏输入信息到最终看到网页的全过程,涉及网络协议以及前后端技术
  • 我开源了一套springboot3快速开发模板
  • 八大架构宪法 - 技术使用指导说明文档
  • GitHub OAuth 认证示例
  • 人人都是音乐家?腾讯开源音乐生成大模型SongGeneration
  • springboot垃圾分类网站
  • 【Linux仓库】进程概念与基本操作【进程·贰】
  • 3D可视化数字孪生智能服务平台-物联网智控节能控、管、维一体化技术架构
  • C++11 std::thread 多线程编程详解
  • DeepSeek本地部署及应用方法
  • nacos热更新引起tcp激增导致服务不可用
  • 基于Python、tkinter、sqlite3 和matplotlib的校园书店管理系统
  • Java 编程之责任链模式
  • Linux 内核学习(12) --- Linux workqueue
  • 开源AI智能名片链动2+1模式S2B2C商城小程序:破解微商代理模式困局的数字化创新路径