https://kotlinlang.org logo
#compose
Title
# compose
d

dazza5000

04/06/2022, 5:03 PM
I think this has been asked before here: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1633949519417700, but I wanted to ask to see if there were any new discoveries. How is it possible to determine the max height needed for the items in a LazyRow so that you can set that as the height of each item so that the vertical height of the LazyRow doesn't change as you scroll?
a

Adam Powell

04/06/2022, 5:21 PM
It isn't possible, by design. The Lazy layouts are made for exactly one use case: when you have so many items that you don't want UI for all of them to exist at once. If you can't have the UI structures for all of them exist at once, you can't take the max/min of their measurements. If they don't all exist at once then you miss correctness cases where the size of one might change over time and you'd have to update the min/max in response.
If you have few enough items such that it's practical to do this, use a plain Row or Column with a scrolling modifier instead, then you can use the usual intrinsics measurements
d

dazza5000

04/06/2022, 5:29 PM
I think the challenge is that Row / Column doesn't support snapping and the defacto library, snapper, doesn't seem to support Row/Column - or is there another way to get snapping on a Row?
also, thank you for the quick/timely response ❤️
👍 1
a

Adam Powell

04/06/2022, 7:36 PM
you can do anything you like re. programmatic scrolling and snapping with the scroll state object passed to the associated modifier
c

Chris Sinco [G]

04/06/2022, 8:33 PM
@dazza5000 It'd also be helpful to get a mock of what you're trying to build to better understand your needs
d

dazza5000

04/06/2022, 8:34 PM
I would like something that could account for this circumstance
right now I am attempting to resize the card based on how much the longest string will take (based on the first cards text layout characteristics) here is some imperfect logic that doesn't account for wrapping
Copy code
val largestTitleTextLength: BasicCardModel? =
                carouselModel.maxByOrNull { it.title?.length ?: 0 }

            val textLayout: (TextLayoutResult) -> Unit = {
                Log.d("darran", "darran layout $it")
                val textCharacterLength = it.layoutInput.text.length
                val textLayoutWidth = it.multiParagraph.width

                val widthPerCharacter = textLayoutWidth / textCharacterLength * it.lineCount

                Log.d("darran", "width per character $widthPerCharacter")
                Log.d("darran", "lineCount ${it.lineCount}")

                val maxWidth = it.layoutInput.constraints.maxWidth

                val heightPerLine = it.multiParagraph.height / it.lineCount

                val totalWidthNeeded =
                    (largestTitleTextLength?.title?.length ?: 1) * widthPerCharacter

                val linesRequired: Float = totalWidthNeeded / maxWidth
                val lineCeiling = ceil(linesRequired)
                Log.d("darran", "linesCeiling ${lineCeiling}")

                val titleHeight = heightPerLine * linesRequired

                Log.d(
                    "darran",
                    "height calculated by textLayoutResult needed ${it.multiParagraph.height}"
                )
                Log.d("darran", "height calculated by algo  needed $titleHeight")
                Log.d("darran", "height overflowhappened ${it.didOverflowHeight} ")
                Log.d("darran", "width overflowhappened ${it.didOverflowWidth} ")

                if (it.multiParagraph.height > titleHeightToSendDown ?: 0f) {
                    titleHeightToSendDown = it.multiParagraph.height
                }

                if (titleHeight > titleHeightToSendDown ?: 0f) {
                    titleHeightToSendDown = titleHeight
                }

                Log.d("darran", "title height to send down $titleHeightToSendDown")
            }
z

Zoltan Demant

04/07/2022, 4:14 AM
Its not perfect, *but it will match the largest child that has been rendered thus far*; Im using a magic number of
224.dp
as the initial one - you can do whatever you like there, this works great for my use case!
Copy code
var minHeight by remember {
    mutableStateOf(224.dp)
}

Modifier
    .onSizeChanged { size ->
        val itemHeight = with(density) {
            val height = size.height
            height.toDp()
        }

        if (itemHeight > minHeight) {
            minHeight = itemHeight
        }
    }
    .heightIn(
        min = minHeight
    )
🍕 1
👍 1
d

dazza5000

04/07/2022, 5:02 PM
@David Corrado this bottom solution posted by @Zoltan Demant is not perfect, but will at least maintain a size of the largest rendered card.
came up with this
Copy code
var minHeight: Dp? by remember { mutableStateOf(null) }
    val density = LocalDensity.current

    val cardSizeModifier = Modifier.onSizeChanged { size ->
        val itemHeight = with(density) {
            val height = size.height
            height.toDp()
        }

        if (itemHeight > minHeight ?: 0.dp) {
            minHeight = itemHeight
        }
    }.defaultMinSize(minHeight = minHeight ?: Dp.Unspecified)
thank you all for the help ❤️
4 Views