Jetpack Compose Desktop中竖线无法与横线对齐的问题排查
问题描述
我正在学习Kotlin和Jetpack Compose Desktop,已经完成数独求解器开发,目前制作其图形界面。窗口尺寸设为800×800,四边均有20.dp内边距。横线绘制公式正常,但竖线出现偏移,且Canvas宽高小于窗口声明尺寸,调整列高度时画线符合预期。


数独界面Composable代码
@Composable fun displayPuzzle(answer: Array<Array<IntArray>>) { var list = mutableStateListOf<String>() for (x in answer[0]) list.addAll(x.map { it.toString() }) var columnHeighty by remember { mutableStateOf(0F) } var columnWidthx by remember { mutableStateOf(0f) } var pad = 20 LazyVerticalGrid( columns = GridCells.Fixed(9), contentPadding = PaddingValues( start = pad.dp, top = pad.dp, end = pad.dp, bottom = pad.dp ) ) { items(list.size) { index -> Card( backgroundColor = Color.Red, modifier = Modifier .fillMaxWidth() .fillMaxHeight() .onGloballyPositioned { coordinates -> columnWidthx = coordinates.size.width.toFloat() columnHeighty = coordinates.size.height.toFloat() }, border = BorderStroke(width = 1.dp, color = Color.White) ) { Text( text = list[index], fontWeight = FontWeight.Bold, fontSize = 30.sp, color = Color(0xFF000000), textAlign = TextAlign.Center, modifier = Modifier.padding(23.dp) ) } } } Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height val strokeWidth = 5.0F println("Canvas Width $canvasWidth") println("Canvas Height $canvasHeight") println("Column Width $columnWidthx") println("Column Height $columnHeighty") //Draw 1st vertical separator drawLine( start = Offset(x = columnWidthx * 3 + pad.toFloat(), y = pad.toFloat()), end = Offset(x = columnWidthx * 3 + pad.toFloat(), y = canvasHeight - pad.toFloat()), color = Color.Black, strokeWidth = strokeWidth ) //Draw 2nd vertical separator drawLine( start = Offset(x = columnWidthx * 6 + pad.toFloat(), y = pad.toFloat()), end = Offset(x = columnWidthx * 6 + pad.toFloat(), y = canvasHeight - pad.toFloat()), color = Color.Black, strokeWidth = strokeWidth ) //Draw 1st horizontal separator drawLine( start = Offset(x = pad.toFloat(), y = columnHeighty * 3 + pad.toFloat()), end = Offset(x = canvasWidth - pad.toFloat() , y = columnHeighty * 3 + pad.toFloat()), color = Color.Black, strokeWidth = strokeWidth ) //Draw 2nd horizontal seperator drawLine( start = Offset(x = pad.toFloat(), y = columnHeighty * 6 + pad.toFloat()), end = Offset(x = canvasWidth - pad.toFloat() , y = columnHeighty * 6 + pad.toFloat()), color = Color.Black, strokeWidth = strokeWidth ) //Draw top border drawLine( start = Offset(x = pad.toFloat(), y = pad.toFloat() + strokeWidth / 2), end = Offset(x = canvasWidth - pad.toFloat() , y = pad.toFloat() + strokeWidth / 2), color = Color.Black, strokeWidth = strokeWidth ) //Draw bottom border drawLine( start = Offset(x = pad.toFloat(), y = canvasHeight - pad.toFloat() - strokeWidth / 2), end = Offset(x = canvasWidth - pad.toFloat() , y = canvasHeight - pad.toFloat() - strokeWidth / 2), color = Color.Black, strokeWidth = strokeWidth ) //Draw left border drawLine( start = Offset(x = pad.toFloat(), y = pad.toFloat()), end = Offset(x = pad.toFloat() , y = canvasHeight - pad.toFloat()), color = Color.Black, strokeWidth = strokeWidth ) //Draw right border drawLine( start = Offset(x = canvasWidth - pad.toFloat(), y = pad.toFloat()), end = Offset(x = canvasWidth - pad.toFloat() , y = canvasHeight - pad.toFloat()), color = Color.Black, strokeWidth = strokeWidth ) } }
窗口初始化代码
Window(onCloseRequest = ::exitApplication) { window.minimumSize = Dimension(800,800) displayPuzzle(finalAnswer[0]) }
解决方案
问题根源
- Canvas尺寸异常:LazyVerticalGrid与Canvas为同级Composable,默认会按垂直顺序排列,Canvas仅能占据Grid剩余空间,无法填满整个窗口,导致其宽高小于窗口声明尺寸。
- 竖线偏移:
columnWidthx仅为单个Card的宽度,但LazyVerticalGrid默认存在列间距,计算竖线位置时未考虑该间距,导致偏移。
修复步骤
- 让Canvas覆盖整个窗口:用
Box包裹LazyVerticalGrid和Canvas,使Canvas叠在Grid上方并填满整个Box(即窗口):
Box(modifier = Modifier.fillMaxSize()) { LazyVerticalGrid(/* 原Grid代码 */) { /* 原items代码 */ } Canvas(modifier = Modifier.fillMaxSize()) { /* 原绘制代码 */ } }
修正竖线位置计算:
- 禁用Grid默认间距:设置
horizontalArrangement = Arrangement.spacedBy(0.dp)和verticalArrangement = Arrangement.spacedBy(0.dp),避免间距干扰宽度计算。 - 获取Grid整体宽度:给Grid添加
onGloballyPositioned获取整体宽度,计算每列实际宽度(含无间距的均匀分配):var gridWidth by remember { mutableStateOf(0f) } // ... LazyVerticalGrid( modifier = Modifier.onGloballyPositioned { gridWidth = it.size.width.toFloat() }, horizontalArrangement = Arrangement.spacedBy(0.dp), verticalArrangement = Arrangement.spacedBy(0.dp), // 其他参数不变 ) val actualColumnWidth = gridWidth / 9 - 用
actualColumnWidth替代columnWidthx计算竖线位置。
- 禁用Grid默认间距:设置
统一单位转换:将
pad.toFloat()替换为pad.dp.toPx(),确保dp与像素单位一致,避免内边距计算偏差。
完整修复后核心代码片段
@Composable fun displayPuzzle(answer: Array<Array<IntArray>>) { var list = mutableStateListOf<String>() for (x in answer[0]) list.addAll(x.map { it.toString() }) var columnHeighty by remember { mutableStateOf(0F) } var gridWidth by remember { mutableStateOf(0f) } val pad = 20 val padPx = pad.dp.toPx() Box(modifier = Modifier.fillMaxSize()) { LazyVerticalGrid( columns = GridCells.Fixed(9), contentPadding = PaddingValues(pad.dp), horizontalArrangement = Arrangement.spacedBy(0.dp), verticalArrangement = Arrangement.spacedBy(0.dp), modifier = Modifier.onGloballyPositioned { gridWidth = it.size.width.toFloat() } ) { items(list.size) { index -> Card( backgroundColor = Color.Red, modifier = Modifier .fillMaxWidth() .fillMaxHeight() .onGloballyPositioned { columnHeighty = it.size.height.toFloat() }, border = BorderStroke(width = 1.dp, color = Color.White) ) { Text( text = list[index], fontWeight = FontWeight.Bold, fontSize = 30.sp, color = Color.Black, textAlign = TextAlign.Center, modifier = Modifier.padding(23.dp) ) } } } Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height val strokeWidth = 5.0F val actualColumnWidth = gridWidth / 9 // 绘制竖线 drawLine( start = Offset(x = actualColumnWidth * 3 + padPx, y = padPx), end = Offset(x = actualColumnWidth * 3 + padPx, y = canvasHeight - padPx), color = Color.Black, strokeWidth = strokeWidth ) drawLine( start = Offset(x = actualColumnWidth * 6 + padPx, y = padPx), end = Offset(x = actualColumnWidth * 6 + padPx, y = canvasHeight - padPx), color = Color.Black, strokeWidth = strokeWidth ) // 其余横线、边框绘制按同样逻辑替换单位与宽度计算方式 } } }
内容的提问来源于stack exchange,提问作者JD74
相关产品推荐
相关产品推荐

