Reputation: 992
I'm making an isometric grid and using padding for it cells. Currently as parameters I'm waiting for its items width and height. But how can I avoid this and use final cells size in an optimal way?
I tried some solutions (commented code is the original way) from this question but it doesn't look legit for the case: I have extra multiple calculations, an error: Padding must be non-negative
and it doesn't show correctly in Android Studio preview.
Modifier.onGloballyPositioned
also looks same and incorrect for the case, what's the right way?
@Composable
fun <T> IsometricGrid(
gridWidth: Int,
gridHeight: Int,
cellWidth: Int,
cellHeight: Int,
data: List<T>,
itemContent: @Composable (Int, T) -> Unit
) {
var width by remember { mutableStateOf(0) }
var height by remember { mutableStateOf(0) }
for (y in 0 until gridHeight) {
for (x in 0 until gridWidth) {
// val start = (y % 2 * 0.5 + x) * cellWidth
// val top = y * cellHeight * 0.5
val index = x * gridHeight + y
Box(
modifier = Modifier
.onSizeChanged {
width = it.width
height = it.height
Timber.i("$width, $height")
}
// .padding(start = start.dp, top = top.dp)
.padding(start = ((y % 2 * 0.5 + x) * cellWidth).dp, top = (y * height * 0.5).dp)
) {
itemContent(index, data[index])
}
}
}
}
Added usage:
IsometricGrid(4, 4, 100, 50, listOf<Foo>(...)) { index: Int, foo: Foo ->
Icon(...)
}
Upvotes: 0
Views: 1524
Reputation: 66674
start = (y % 2 * 0.5 + x * width).dp, top = (y * height * 0.5).dp
This line is not correct because you add dp extension to pixel instead of converting pixel to dp
What you should be doing
val density = LocalDensity.current
density.run{(y % 2 * 0.5 + x * width).toDp()}
because dp value of any pixel values is calculated as
dpValue = valueInPixel/density
let's say you have 100px with a density = 2.0f
your dp value should be 50.dp. If you calculate it as in your question you find that it returns 100.dp
Try this. I don't have data, so i'm not able to try your function.
@Composable
fun <T> IsometricGrid(
gridWidth: Int,
gridHeight: Int,
cellWidth: Int,
cellHeight: Int,
data: List<T>,
itemContent: @Composable (Int, T) -> Unit
) {
val density = LocalDensity.current
var width by remember { mutableStateOf(0) }
var height by remember { mutableStateOf(0) }
for (y in 0 until gridHeight) {
for (x in 0 until gridWidth) {
// val start = (y % 2 * 0.5 + x) * cellWidth
// val top = y * cellHeight * 0.5
val index = x * gridHeight + y
val startInDp = density.run { ((y % 2 * 0.5f + x) * cellWidth).toDp() }
val topInDp = density.run { (y * height * 0.5f).toDp() }
Box(
modifier = Modifier
.onSizeChanged {
width = it.width
height = it.height
}
// .padding(start = start.dp, top = top.dp)
.padding(
start = startInDp,
top = topInDp
)
) {
itemContent(index, data[index])
}
}
}
}
toDp() is extension for Float in Density interface
/** Convert a [Float] pixel value to a Dp */
@Stable
fun Float.toDp(): Dp = (this / density).dp
Upvotes: 2