如何在 Compose 中制作这种不均匀的网格?

问题描述 投票:0回答:3

我一直在深入研究 Jetpack Compose。在这里,我使用行、列和间隔符来构建此屏幕截图。有更适合我应该尝试的可组合项吗?

grid

我无法让 LazyVerticalGrid 将水母放置在其位置。它想把它放在黑狗下方的左侧,这样会留下一个空白空间,并将棕色狗推到自己的线上。

我还尝试了Accompanist的FlowRow,它绘制了与LazyVerticalGrid相同的排列。也可能我对两者的 API 都不够熟悉。

后来我想学习拖放来重新排序项目。当我设置这个小部件以使生活更轻松时,是否需要考虑一些因素?在我看来,这些单独的行和列可能会妨碍我,但也许没有影响。

感谢您的任何见解!

android android-studio kotlin android-jetpack-compose
3个回答
0
投票

Google jetpack 撰写路径有关于自定义布局的课程,但我认为您可以使用

Lazy Grid
,它可以轻松使用网格。

链接 Android 开发者 Lazy Grids 如果您单击

lazy vertical grid
链接,您将看到可以有多行带有
different modifiers and number of grid cells
的项目。

我很乐意给您一个有效的示例,所以我可能会很快编辑它。


0
投票

我的此类网格的自定义布局的简单版本如下所示:

@Composable
fun GalleryScreen(
    items: List<String>
) {
    GalleryGrid(
        modifier = Modifier.fillMaxWidth(),
        contentPadding = PaddingValues(16.dp)
    ) {
        items.forEach { url ->
            AsyncImage(url = url)
        }
    }
}

@Composable
fun GalleryGrid(
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues,
    content: @Composable () -> Unit
) {
    val scrollState = rememberScrollState()
    Layout(
        modifier = modifier.verticalScroll(state = scrollState),
        measurePolicy = rememberMeasurePolicy(
            contentPadding = contentPadding
        ),
        content = content
    )
}

@Composable
private fun rememberMeasurePolicy(
    contentPadding: PaddingValues
): MeasurePolicy = remember(contentPadding) {
    GalleryGridMeasurePolicy(contentPadding)
}

private class GalleryGridMeasurePolicy(
    private val contentPadding: PaddingValues
) : MeasurePolicy {

    override fun MeasureScope.measure(measurables: List<Measurable>, constraints: Constraints): MeasureResult {
        val start = contentPadding.calculateLeftPadding(LayoutDirection.Ltr).roundToPx()
        val top = contentPadding.calculateTopPadding().roundToPx()
        val end = contentPadding.calculateRightPadding(LayoutDirection.Ltr).roundToPx()
        val bottom = contentPadding.calculateBottomPadding().roundToPx()

        val width = constraints.maxWidth
        val itemWidth = (width - start - end) / GalleryGridDefaults.SpanCount
        val firstItemWidth = itemWidth * GalleryGridDefaults.FirstItemSpanCount

        var height = top
        var rowHeight = 0
        val itemHeight = (itemWidth / GalleryGridDefaults.AspectRatio).roundToInt()

        val placeablesWithOffset = measurables
            .take(GalleryGridDefaults.MaxPhotoCount)
            .mapIndexed { index, measurable ->
                when (index) {
                    // 1 row, 1 item
                    0 -> {
                        val firstItemHeight = itemHeight * GalleryGridDefaults.FirstItemSpanCount
                        rowHeight = firstItemHeight
                        height += rowHeight
                        measurable.measure(
                            Constraints(
                                minWidth = firstItemWidth,
                                maxWidth = firstItemWidth,
                                minHeight = firstItemHeight,
                                maxHeight = firstItemHeight
                            )
                        ) to IntOffset(
                            x = start,
                            y = top
                        )
                    }
                    // 1 row, 2 item
                    1 -> {
                        measurable.measure(
                            Constraints(
                                minWidth = itemWidth,
                                maxWidth = itemWidth,
                                minHeight = itemHeight,
                                maxHeight = itemHeight
                            )
                        ) to IntOffset(
                            x = start + firstItemWidth,
                            y = top
                        )
                    }
                    // 1 row, 3 item
                    2 -> {
                        measurable.measure(
                            Constraints(
                                minWidth = itemWidth,
                                maxWidth = itemWidth,
                                minHeight = itemHeight,
                                maxHeight = itemHeight
                            )
                        ) to IntOffset(
                            x = start + firstItemWidth,
                            y = top + itemHeight
                        )
                    }
                    // others
                    else -> {
                        val column = index % GalleryGridDefaults.SpanCount
                        if (column == 0) {
                            rowHeight = itemHeight
                            height += rowHeight
                        }
                        measurable.measure(
                            Constraints(
                                minWidth = itemWidth,
                                maxWidth = itemWidth,
                                minHeight = itemHeight,
                                maxHeight = itemHeight
                            )
                        ) to IntOffset(
                            x = start + column * itemWidth,
                            y = height - rowHeight
                        )
                    }
                }
            }

        return layout(width, height + bottom) {
            placeablesWithOffset.forEach { (placeable, offset) ->
                placeable.place(offset)
            }
        }
    }
}

private object GalleryGridDefaults {
    const val SpanCount = 3
    const val MaxPhotoCount = 9
    val AspectRatio = 1f
    const val FirstItemSpanCount = 2
}

-2
投票

我制作了一个自定义的

Layout
,它允许测量和放置内容。 🤞🏽

© www.soinside.com 2019 - 2024. All rights reserved.