Does anyone have a suggestions on how I could make...
# compose
d
Does anyone have a suggestions on how I could make this a reusable component / modifier?
a
That looks pretty unstable; at a minimum it creates a data dependency where composition depends on layout, which will never resolve in a single frame. What are you trying to do?
d
you can see what I am trying to do in the original thread https://kotlinlang.slack.com/archives/CJLTWPH7S/p1649264638345149
a
ok, so it's predicated on misuse of LazyRow. This is a dead end; you're not going to be able to implement something free of jank/edge cases this way since you're depending on backtracking in both composition and layout that can't happen within a single frame. It's going to lead to flickering UIs and it will be difficult to test.
If you're using this modifier on multiple row children then that's where the backtracking within layout comes from even if the backtracking in composition is resolved
even if you could resolve the layout backtracking part, you would still get a UI where the user could scroll the row and suddenly its height would grow mid-scroll
k
If the content is loaded lazily, how do you know the "max" height of yet-unloaded elements?
a
exactly, you don't
now, presuming you're determined enough to ignore all of the above and do it anyway, you can use
Modifier.layout
instead of
defaultMinSize
so that you can work in pixels rather than having to consult
LocalDensity
, then you could factor out an explicit hoisted state object to hold the max, passing that same hoisted state object any time you use the modifier. Custom modifiers are written using extension functions, so you could do
Copy code
fun Modifier.myJumpyHeight(state: MyJumpyHeightState) = onSizeChanged { ... }.layout { ... }
d
i am determined to ignore all common sense and warnings
😂 1
a
so long as we're on the same page there 😄
d
indeed 🙂
another noob question - does the state object need to have any characterists/interfaces implemented to be persisted across composition or to just be
remembered
when defined
like it doesn't need to have it's properties in saver or anything special......or...does it?
a
only if you want it to. Its properties that you want to be observable and cause relayout/recomposition should be
by mutableStateOf
, etc. but other than that, nothing special
🍕 1
d
I didn't migrate to use .layout yet, but this is what I have so far
Copy code
fun Modifier.myJumpyHeight(state: MyJumpyHeightState, density: Density) = onSizeChanged { size ->
    val itemHeight = with(density) {
        val height = size.height
        height.toDp()
    }

    if (itemHeight > state.minHeight ?: 0.dp) {
        state.minHeight = itemHeight
    }
}.defaultMinSize(minHeight = state.minHeight ?: Dp.Unspecified)

data class MyJumpyHeightState(var minHeight: Dp? = null)
and it works
I define these in a parent composable
Copy code
val density = LocalDensity.current

    var myJumpyHeightState by remember { mutableStateOf(MyJumpyHeightState()) }
and then pass it in as a modifier of an item that is part of a
LazyRow
a
never use a
var
in a
data class
constructor param, compose or no compose; it means you have unstable equality and hash codes over time. The former you can rationalize in some circumstances, the latter is a Problem(TM) if someone ever uses one as the key in a map
👍 1
you'll want that to be defined as
Copy code
class MyJumpyHeightState(minHeight: Int = 0) {
  var minHeight by mutableStateOf(minHeight)
}
and then use
val myJumpyHeightState = remember { MyJumpyHeightState() }
instead of the external
mutableStateOf
👍 1
d
sorry for reviving this, but are there any new solutions for this that have been developed in the past year?
we're still using this in production