今天大概会聊到的范围
- Intrinsic measurements
今天的标题可能会让人有点疑惑,但这是我写出这段 Code 时的第一反应。
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier
.background(Color.White)
.padding(4.dp)
) {
Text(text = "Title", style = titleStyle)
Text(text = "Looooooooooooooog Text")
Spacer(modifier = Modifier.size(16.dp))
Button(onClick = {}, modifier = Modifier.fillMaxWidth()) {
Text(text = "GO")
}
}
这是一个 Dialog,在这个 Dialog 中,我希望整个 Dialog 和最宽的 Text 一样宽,底部的 Button 可以是一个横向、占据整个底部的按钮。直觉上,因为 Button 预期是最宽的状态,所以我写了 fillMaxWidth
。但我最後得到的画面却是这样:
按钮就真的给我 fillMaxWidth
了,但因为没有任何 constraint ,所以按钮就一路延伸到和装置的画面一样宽。
要解决这个问题前,要先了解 Compose 在测量 child 的大小时只会测量一次。就如同上一次聊到的一样,每个 parent 在测量自己的大小前,都会先测量一次 child 的大小。都测量完之後,parent 才会知道自己多大。但这边就出现了一个问题,因为测量 Button 时,parent 并不知道自己多大,也没有特别的 constraint 传给 Button,因此 Button 就回给 parent 自己要要和 max width 一样大。
当然,我们可以在 parent ( Column
这一层 ) 写死固定的 width 来设定 Dialog 大小,但这就没办法符合动态和最宽的文字一样宽的需求。
这边就要介绍到 Intrinsic measurements。Compose 的系统中设计了一个可以让 parent 可以先知道 child 可能会多大。
每一个 Composable 都会有四个资料
IntrinsicMeasureScope.minIntrinsicWidth
IntrinsicMeasureScope.minIntrinsicHeight
IntrinsicMeasureScope.maxIntrinsicWidth
IntrinsicMeasureScope.maxIntrinsicHeight
( min | max )Intrinsic( Width | Height )
都是在 InstrinsicMeasureScope
上,至於被使用的时机晚点会提到。因为在实际使用时,我们不会需要手动去取得这四个资料。而是透过 IntrinsicSize.(Max | Min)
来表示最大 or 最小
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier
.background(Color.White)
.padding(4.dp)
.width(IntrinsicSize.Max) // 将 width 设定为测量前最大的 child 大小
) {
Text(text = "Title", style = titleStyle)
Text(text = "Looooooooooooooog Text")
Spacer(modifier = Modifier.size(16.dp))
Button(onClick = {}, modifier = Modifier.fillMaxWidth()) {
Text(text = "GO")
}
}
当你将 height
/width
等设定成 IntrinsicSize.(Max | Min)
後,实际上会在 modifier chain 中增加一个 IntrinsicSizeModifier
。这个 Modifier 是一个 LayoutModifer,在计算 constraint 时会去参考 composable 提供的 intrinsic measurement。
// 设定 width(IntrinsicSize.Max) 时,就会在 modifier 中增加一个 MaxIntrinsicWidthModifier
private object MaxIntrinsicWidthModifier : IntrinsicSizeModifier {
// modifier 中,会覆写 constraint 的计算逻辑
override fun MeasureScope.calculateContentConstraints(
measurable: Measurable,
constraints: Constraints
): Constraints {
// 计算时,会参考 measurable 的 intrinsic size
// 就是上面提到的 ( min | max )Intrinsic( Width | Height )
val width = measurable.maxIntrinsicWidth(constraints.maxHeight)
return Constraints.fixedWidth(width)
}
}
最後我们就可以产出一个以内容为大小依据的 Dialog,包含一个填满 Dialog 的按钮。
今天实际的 code 其实不会很复杂,逻辑也很好理解。只是研究时发现和之前聊到的 Layout 逻辑整个串在一起,觉得很有趣。Compose 有很好的 render 逻辑,让 measure 的次数降到最低。Intrinsic measurement 则是在这个结构下产生的好用工具。
Reference:
<<: Day8 - 布署 GitHub 程序与串接聊天机器人 LINE Messaging API
摘要 Test资料集验证 1.1 单张图档预测 1.2 多张图档预测 五个模型的准确度对照表 心得 ...
今天介绍两个粒子效果应用范例,一个是透过按键控制粒子效果生成以及删除,第二个是制作炸弹炸物体产生的效...
Machine learning is now a product engineering dis...
初版待更新(还是翻新),9月19日中秋节前夕,爬山旅行中。 网路收讯极差,慌张的寻找网路与讯号点。 ...
今天开始要讲分散式系统的一些概念罗。 影片在此: Day04_关於分散式系统的一些概念 (一) ...