We can pass data from a composable to its parent L...
# compose
p
We can pass data from a composable to its parent Layout with ParentDataModifier, so this data can be accessed from the measurable. But how to pass this same data from this layout to its parent layout?
Basically I want the top-most layout to know the height of a specific nested layout , possibly deeply nested (not the immediate child)
Do I need to save the measured height in a
MutableState
owned by the topmost layout through callbacks ? I wanted to avoid it since it may lead the state with invalid data in case some composable forgets to call the callback. If the tagged layout leaves composition, this data should be cleared
p
SubcomposeLayout doesn't work? Basically it tells the children to compose and measure, and the children will do the same down the three accordingly until reaching the nested layer where your component is at. Is a bit performance
p
I don’t see how it could help, SubcomposeLayout allows passing parent constraints to children composables but what I actually need is passing child measured size to (not immediate) parent composable
p
The children will measure itself indirectly. You might not get that nested child metrics directly but you get the size constraints demanded for whatever is between the child and your Layout. Otherwise the callback sounds like the most natural thing to do. Although it has some drawbacks. Let’s wait till someone provides a good answer
a
You want the exact height, or you just want parent to size itself based on children down the tree? https://developer.android.com/jetpack/compose/layouts/intrinsic-measurements could help with the latter
Oh, hmm, you mention ParentDataModifier so perhaps you're familiar with this already
p
Let me expose the exact thing I’m trying to achieve: I’m doing a collapsing toolbar and it’s working fine. It implements collapse/expand through nested scroll modifier. However, it has an annoyance of collapsing when it does not need to. A fix is to check whether the child is filling his whole height or not — If it is not, then toolbar does not need collapsing as content is fully visible. So it only allows collapsing if child height fills the whole constraints size (I’m using onGloballyPositioned on child) This works fine with only a child that is a LazyColumn or Column + verticalScroll. If the lazy column has height X but constraints is bigger than X, I can disable toolbar collapsing But this solution is subpar, especially when child layout is something like “something scrollable + empty space + footer/bottom bar” So I’m trying to communicate to this parent (scrollable toolbar) that “I’m filling the whole height, BUT the actually scrollable content can expand without requiring scrolling”
1
So I wanted to send that information through modifiers ideally, instead of callbacks It must be possible somehow, because that’s exactly what nested scroll does, not sure exactly how. It works even with layouts in the middle
Copy code
Box(Modifier.nestedScroll(…)) {
  Box {
    Box(verticalScroll(…)) {
    }
  }
}
So, vertical scroll info from innermost box still reaches the outermost box even if middle layout has no nested scroll. It somehow connects. I was hoping to do something similar to pass data to outermost composable from innermost composable
Ah, seems what I need is
ModifierLocalProvider
☝🏻 1
👀 1
🔥 1
a
I was not aware of this. Let us know if it works, hopefully without any performance gotchas.
But, just for my clarity, assuming this simple layout:
Copy code
Column {
  CollapsingAppBar
  MainContent
  BottomBar etc
}
You want
CollapsingAppBar
to be collapsible only if
MainContent
extends beyond the height of the screen, yes? Well, this doesn't answer your question but I'd recommend not going down this route. We've tried it back in the classic Android View days (if child is
wrap_content
instead of
match_parent
), and we had user reports telling us the collapse behaviour is bugged "sometimes" (they meant when content was small enough to fit in the screen). Some people just expect things to work the same regardless of the situation, and in any case it's a neat thing for them to play around with. UI always reacts to their touch, you know?
z
I was just about to suggest modifier locals
p
@Zach Klippenstein (he/him) [MOD] thanks, I guess there’s not much documentation around it so I just found out about it when fiddling with nestedScroll source @ascii yeah, Basically I want to disable collapsing behavior if content is not “able” to scroll. Does not make sense to me to scroll just to collapse the top bar. It's something we are already controlling for, but poorly. I’m Not sure how exactly I’ll go about it (maybe content height, maybe leverage scrollState canScrollForward/Backward), I’ll go around experimenting and see if there’s a robust solution to that
1
@ascii actually the layout in my case would be:
Copy code
Toolbar {
  Column {
     MainScrollableContent()
     BottomBar()
  }
}
in my case toolbar is a scaffold with a slot for “the rest of the content”, and not a slot in itself
d
Shouldn't this be fixed (or allowed to be adjusted) in the first party compose libraries instead? Do you have a bug report or a feature request that I can +1 ?
1
p
shouldn’t this be fixed
what exactly? I’m not using Material toolbar or scaffold, it’s custom components.
d
In the ScrollingConnection I suppose, although thinking about it, it probably "works as expected" because 'can't scroll' is treated the same as 'scrolled to the end'.
p
@dorche yeah I think it works as intended. When a scrollable can not scroll neither forward nor backwards, it still reports the scrolling deltas to parent through nested scroll connection so parent can consume it if it wants . Then it consumes 0 after that
I think that's how it works
I think what I want now is either for the scrollable thing to not report deltas upstream if it cannot scroll itself, or for my upstream thing to not consume IF scrollable thing won't consume itself.
Still wiring my neurons around what's the preferable approach here
w
@Patrick Steiger Have you found any solution for this?
p
Did not follow up on this , but latest kinda successful attempt is through ModifierLocalProvider IIRC
👍 1