Trejkaz
07/23/2024, 6:11 AMTrejkaz
07/23/2024, 6:12 AMGridLayout(columnCount = 2) {
val indent = Modifier.padding(start = 8.dp)
row {
Text(text = "Added in:", fontWeight = FontWeight.Bold)
Text(text = "${description.versionInfoSummary.versionString} (${description.versionInfoSummary.versionDateString})")
}
row {
Text(text = "Location:", fontWeight = FontWeight.Bold)
}
row(modifier = indent) {
Text(text = "Block:", fontWeight = FontWeight.Bold)
Text(text = description.blockName)
}
row(modifier = indent) {
Text(text = "Plane:", fontWeight = FontWeight.Bold)
Text(text = description.planeName)
}
row {
Text(text = "Script:", fontWeight = FontWeight.Bold)
Text(text = description.scriptName)
}
row {
Text(text = "Category:", fontWeight = FontWeight.Bold)
Text(text = description.codePointCategory)
}
}
Trejkaz
07/23/2024, 6:12 AMTrejkaz
07/23/2024, 6:12 AMTrejkaz
07/23/2024, 6:13 AMTrejkaz
07/23/2024, 6:14 AMTrejkaz
07/23/2024, 6:24 AMefemoney
07/23/2024, 6:36 AMefemoney
07/23/2024, 6:38 AMTrejkaz
07/23/2024, 6:38 AMephemient
07/23/2024, 6:39 AMTrejkaz
07/23/2024, 6:39 AMefemoney
07/23/2024, 6:43 AMthe bit I can’t figure out is how to mark the rows with the row they belong to so that later I can know which ones belong togetherYou could always add
parentData
aka layoutId
, which you can access from your custom layout measure policy block.
(you will need the custom measurement / layout anyways for the alignment lines)Trejkaz
07/23/2024, 6:44 AMefemoney
07/23/2024, 6:46 AMTrejkaz
07/23/2024, 6:48 AMTrejkaz
07/23/2024, 6:57 AMefemoney
07/23/2024, 6:58 AMalignment lines seem very magicalPersonally I think of alignment lines as specific (horizontal or vertical) lines within any layout node, the position of which is measured from (0, 0) of that node ie
topLeft
corner
A row, column or even custom parent can then read these alignment lines from any of its children and, quite literally, line them up.
So I could for instance add an alignment line right in the middle of all my children and when I align them by that line, their middles will be lined up. Less useful as you dont need an AlignmentLine
for this, its already possible with normal Alignment
parameter.Trejkaz
07/23/2024, 6:58 AMefemoney
07/23/2024, 6:58 AMTrejkaz
07/23/2024, 6:59 AMefemoney
07/23/2024, 6:59 AMTrejkaz
07/23/2024, 7:00 AMTrejkaz
07/23/2024, 7:00 AMefemoney
07/23/2024, 7:04 AMparentData
first.Trejkaz
07/23/2024, 7:05 AMTrejkaz
07/23/2024, 7:06 AMefemoney
07/23/2024, 7:07 AMTrejkaz
07/23/2024, 7:07 AMTrejkaz
07/23/2024, 7:07 AMTrejkaz
07/23/2024, 7:08 AMTrejkaz
07/23/2024, 7:10 AMTrejkaz
07/23/2024, 7:10 AMefemoney
07/23/2024, 7:10 AMTrejkaz
07/23/2024, 7:11 AMTrejkaz
07/23/2024, 7:11 AMTrejkaz
07/23/2024, 7:11 AMefemoney
07/23/2024, 7:13 AMefemoney
07/23/2024, 7:14 AMLayout
a list of composables and for each one in the list, in your measurement block you will get a list of measurables
Its basically the one with a List<List<Measurable>>
efemoney
07/23/2024, 7:17 AMCustomRow.content
• You will map your list of CustomRows into a List<@Composable () -> Unit>
and pass it into the multi content Layout
• MeasurePolicy will have List<List<Measurable>>
with each item in the outer list representing the list of “items” / nodes composed within a single rowefemoney
07/23/2024, 7:20 AMn
items based on columnCount.
• You can take the first (index=0) item for each rows list as the “label” OR you can add a layoutId
to specific composables to denote which one is label & which one is description
• You can say, if this row has only one cell (ie one item) do not use its size to determine label column size, just measure it after ALL other nodes have been measured or whateverTrejkaz
07/23/2024, 7:23 AMefemoney
07/23/2024, 7:23 AMTrejkaz
07/23/2024, 7:23 AMTrejkaz
07/23/2024, 7:23 AMefemoney
07/23/2024, 7:23 AMTrejkaz
07/23/2024, 7:23 AMTrejkaz
07/23/2024, 7:55 AMTrejkaz
07/23/2024, 7:55 AMefemoney
07/23/2024, 7:56 AMTrejkaz
07/23/2024, 7:56 AMefemoney
07/23/2024, 7:57 AMTrejkaz
07/23/2024, 7:58 AMTrejkaz
07/23/2024, 7:58 AMTrejkaz
07/23/2024, 7:59 AMTrejkaz
07/23/2024, 7:59 AMTrejkaz
07/23/2024, 7:59 AMefemoney
07/23/2024, 8:00 AMTrejkaz
07/23/2024, 8:01 AMTrejkaz
07/23/2024, 8:01 AMTrejkaz
07/23/2024, 8:01 AMTrejkaz
07/23/2024, 8:01 AMefemoney
07/23/2024, 8:01 AMTrejkaz
07/23/2024, 8:02 AMTrejkaz
07/23/2024, 8:02 AMTrejkaz
07/23/2024, 8:02 AMTrejkaz
07/23/2024, 8:02 AMefemoney
07/23/2024, 8:03 AMweight(...)
Trejkaz
07/23/2024, 8:03 AMTrejkaz
07/23/2024, 8:05 AMTrejkaz
07/23/2024, 8:06 AMfun main() = singleWindowApplication {
Surface {
Column {
Row {
Text("a")
}
Row {
Text("b")
}
Row {
Text("c")
}
}
}
}
Trejkaz
07/23/2024, 8:06 AMefemoney
07/23/2024, 8:06 AMefemoney
07/23/2024, 8:06 AMTrejkaz
07/23/2024, 8:07 AMTrejkaz
07/23/2024, 8:07 AMefemoney
07/23/2024, 8:07 AMTrejkaz
07/23/2024, 8:07 AMTrejkaz
07/23/2024, 8:07 AMefemoney
07/23/2024, 8:07 AMTrejkaz
07/23/2024, 8:07 AMTrejkaz
07/23/2024, 8:08 AMval columnConstraints = constraints.copy(
maxWidth = (constraints.maxWidth - xOffset).coerceAtLeast(constraints.minWidth)
)
efemoney
07/23/2024, 8:08 AMTrejkaz
07/23/2024, 8:08 AMTrejkaz
07/23/2024, 8:08 AMefemoney
07/23/2024, 8:09 AMfillMaxSize()
for instance like i have in my screen shot it sets the constraints to
minW = maxW = MAX_WIDTH_AVAILABLE
minH = maxH = MAX_HEIGHT_AVAILABLETrejkaz
07/23/2024, 8:09 AMefemoney
07/23/2024, 8:09 AMright, so we have a catch-22 here where I need to measure something to determine how much space it needs so that I can measure itNot really, you just need new constraints for the children
Trejkaz
07/23/2024, 8:10 AMefemoney
07/23/2024, 8:10 AMTrejkaz
07/23/2024, 8:10 AMefemoney
07/23/2024, 8:11 AMTrejkaz
07/23/2024, 8:11 AMTrejkaz
07/23/2024, 8:12 AMTrejkaz
07/23/2024, 8:12 AMTrejkaz
07/23/2024, 8:12 AMefemoney
07/23/2024, 8:12 AMefemoney
07/23/2024, 8:14 AMTrejkaz
07/23/2024, 8:15 AMTrejkaz
07/23/2024, 8:15 AMTrejkaz
07/23/2024, 8:20 AMTrejkaz
07/23/2024, 8:21 AMTrejkaz
07/23/2024, 8:21 AMefemoney
07/23/2024, 8:21 AMI’m not sure how much it should take if it’s fighting with the other columns over the available widthThis is dependent on you unfortunately. You have limited space: eg 400 wide. You have n number of columns You want, say, first column to be as wide as its widest child You see the issue? Its widest child could just want to take up all the space, and you will need to decide how to constrain it from doing so. You do that with the constraints you pass in for it to measure with. If, for example, you have 3 column but your 1st column is your priority column and the max width it can be is half entire width, and the rest of the columns will share the remaining space equally; you’ll measure all the first items with
new Constraints (
minW = 0, maxW = constraints.maxW / 2,
minH = 0, maxH = constraints.maxH
)
which means their width can be anywhere from 0 - halfFullWidth. Iterate through all, and find the max width. Subtract that from the main constraints max width and then divide by 2 to get the other columns’ max width that should be used to measure themTrejkaz
07/23/2024, 8:22 AMTrejkaz
07/23/2024, 8:23 AMTrejkaz
07/23/2024, 8:24 AMefemoney
07/23/2024, 8:24 AMspecifying the min sizes as 0 appears to have made it behave itselfyes because like I said earlier, when you tell a parent to fillMaxWidth (or fillMaxSize), its a directive to set the constraints at that point like so minW = maxW = MAX_WIDTH_AVAILABLE minH = maxH = MAX_HEIGHT_AVAILABLE So if you pass this to a node to measure, youre basically telling it that the minimum space it should take is the entire space … and it has to respect that (usually)
efemoney
07/23/2024, 8:24 AMefemoney
07/23/2024, 8:25 AMfillMaxHeight()
because, well, it doesnt make sense 😅Trejkaz
07/23/2024, 8:26 AMTrejkaz
07/23/2024, 8:26 AMefemoney
07/23/2024, 8:26 AMTrejkaz
07/23/2024, 8:26 AMTrejkaz
07/24/2024, 2:05 AMTrejkaz
07/24/2024, 2:19 AMval scope = GridLayoutScope()
println("About to call GridLayout scope lambda") <- only gets here once
scope.content()
println("Call to scope lambda returned, row count = ${scope.rows.size}") <- only gets here once
Layout(
contents = scope.rows.map { r -> r.content },
modifier = modifier
) { measurables: List<List<Measurable>>, constraints: Constraints ->
println("Inside Layout MeasureScope, measurables = (size ${measurables.size}) $measurables") <- does call this twice
efemoney
07/24/2024, 9:20 AMGridLayout(
…
content: GridLayoutScope.() -> Unit // Note: NOT composable
)
interface GridLayoutScope {
fun row(
…
content: @Composable () -> Unit
)
}
In which case you’d do a trick like LazyItemProvider does (linked somewhere above)Trejkaz
07/24/2024, 9:21 AMTrejkaz
07/24/2024, 9:22 AMefemoney
07/24/2024, 9:22 AMTrejkaz
07/24/2024, 9:22 AMefemoney
07/24/2024, 9:24 AMefemoney
07/24/2024, 9:25 AMGridLayout(
...
rows: List<@Composable () -> Unit>
)
Trejkaz
07/24/2024, 9:25 AMefemoney
07/24/2024, 9:25 AMGridLayout(
...
rowCount: Int,
content: List<@Composable (Int) -> Unit>,
)
Trejkaz
07/24/2024, 9:25 AMTrejkaz
07/24/2024, 9:25 AMTrejkaz
07/24/2024, 9:26 AMTrejkaz
07/24/2024, 9:26 AMTrejkaz
07/24/2024, 9:27 AMefemoney
07/24/2024, 9:27 AMScaffold
in your GridLayout content lambda and does NOT call row { ... }
, what would that sort of layout mean?Trejkaz
07/24/2024, 9:27 AMTrejkaz
07/24/2024, 9:27 AMefemoney
07/24/2024, 9:27 AMmagical cachingin compose. Its all well defined behavior
Trejkaz
07/24/2024, 9:28 AMTrejkaz
07/24/2024, 9:28 AMefemoney
07/24/2024, 9:28 AMI have no idea eitherYour API should not allow such a case
Trejkaz
07/24/2024, 9:28 AMTrejkaz
07/24/2024, 9:28 AMTrejkaz
07/24/2024, 9:28 AMefemoney
07/24/2024, 9:28 AMTrejkaz
07/24/2024, 9:29 AMTrejkaz
07/24/2024, 9:29 AMefemoney
07/24/2024, 9:30 AMTrejkaz
07/24/2024, 9:30 AMTrejkaz
07/24/2024, 9:30 AMclass GridLayoutScope {
val rows = mutableListOf<CustomRow>()
fun row(content: @Composable () -> Unit) {
rows.add(CustomRow(content = content))
}
}
efemoney
07/24/2024, 9:30 AMTrejkaz
07/24/2024, 9:30 AMval rowContents by derivedStateOf {
val scope = GridLayoutScope()
scope.content()
scope.rows.map { r -> r.content }
}
Layout(
contents = rowContents,
modifier = modifier
) { ... }
Trejkaz
07/24/2024, 9:31 AMefemoney
07/24/2024, 9:31 AMTrejkaz
07/24/2024, 9:31 AMTrejkaz
07/24/2024, 9:31 AMTrejkaz
07/24/2024, 9:31 AMefemoney
07/24/2024, 9:32 AMTrejkaz
07/24/2024, 9:32 AMTrejkaz
07/24/2024, 9:35 AMTrejkaz
07/24/2024, 9:35 AMTrejkaz
07/24/2024, 9:35 AMephemient
07/25/2024, 8:28 AMTrejkaz
07/25/2024, 8:34 AMTrejkaz
07/25/2024, 8:37 AMephemient
07/25/2024, 8:39 AMephemient
07/25/2024, 8:54 AMTrejkaz
07/25/2024, 8:57 AMTrejkaz
07/25/2024, 8:57 AMephemient
07/25/2024, 9:00 AMephemient
07/25/2024, 9:00 AMephemient
07/25/2024, 9:02 AM