Column + m3.TopAppBar (with contentPadding) + Inse...
# compose
s
Column + m3.TopAppBar (with contentPadding) + Insets question 🧵
Got a layout which looks kinda like this:
Copy code
Column(.verticalScroll().windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal))) {
  TopAppBar(
    contentPadding = WindowInsets.safeDrawing.only(<http://WindowInsetsSides.Top|WindowInsetsSides.Top> + WindowInsetsSides.Horizontal).asPaddingValues(),
  )
  Stuff()
  Spacer(windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom)))
}
But this way, the TopAppBar gets the horizontal padding applied to it which I do not want as the top app bar now doesn’t go edge to edge when in landscape mode and there’s navigation buttons, as that should be handled by the insets passed in its contentPadding. Is there some way to achieve my goal with this structure, or do I have to make it so that I do something like
Copy code
Column(.verticalScroll()) {
  TopAppBar(
    contentPadding = WindowInsets.safeDrawing.only(<http://WindowInsetsSides.Top|WindowInsetsSides.Top> + WindowInsetsSides.Horizontal).asPaddingValues(),
  )
  Column(
    .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal))
    .weight(1f) // <-- got some problems with this
  ) {
    Stuff()
    Spacer(windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom)))
  }
}
But I can’t go with #2 (unless I fix this somehow), as that way if I put the weight(1f) on the inner column, it doesn’t scroll at all when the content fills the entire height. And if I don’t put the weight(1f) the inner column doesn’t take up the entire space, so this column in column situation is more tricky than I’d like it to be.
I wonder if I should in this case have a nestedScroll situation, since I do want the TopAppBar i this case to also scroll away so both those two columns need to be scrollable. šŸ¤”
t
I don't really understand what exactly you're trying to achieve, I found your message a bit confusing but I noticed something related to system paddings. Did you try to use
Scaffold
instead of
Column
? It has a lambda specially for
TopAppBar
content that's supposed to handle the system paddings properly for you.
s
Yeah you’re right it was me blurting out all my thoughts in a message, I’ll try to explain better. I have a column, which has a top app bar, and some content. I want the top app bar to act like a simple item in the column, not have it be part of a scaffold, but it will scroll away as I scroll the screen downwards. Now in order to properly go edge to edge, I am applying the insets padding to that outer column, so that the contents render inside the safe drawing space. This isn’t optimal for my top app bar, since that one I don’t want to get that padding, but actually go edge to edge, while still getting the correct contentPadding to it, so that the inner buttons are drawn correctly, yet the background it has goes edge to edge. So since I can’t really have a column apply padding only to certain items, I thought of having one outer column, containing this TopAppBar, but not giving any instructions about insets. And then this inner column can do the instetting instead. This works, but I then get the issue that since the outer column is scrollable, it wraps the content height, and it doesn’t let me have (in the case where the entire content doesn’t use the entire height) the structure of TopAppBar Content that takes up all the rest of the available screen space But instead makes it so that it’s then TopAppBar Content Empty space that I can’t fill. If I mitigate this by putting weight(1f) in the inner column, this makes it so that the outer column no longer scrolls, since it’s only giving it ā€œthe restā€ of the space available, so there isn’t anything to scroll towards, hiding the contents that go out of screen of this inner column. So this can be summarized to two problems, if I solve one of the two i’d be good. • Can’t un-do some padding to only 1 of the column items I technically can, but forcing that 1 child to force take more space horizontally according to the horizontal insetsPadding using a
layout()
modifier or something like that, but I’d rather avoid this, as it’d look quite complex I think. • I can’t put a column inside a scrolling column and still have it force take up the entire screen height when there is no need to scroll, while also letting it take up more than the available space when there is enough content in order to warrant scrolling. I know this may be too much, if anything it’s serving as a way for myself to rubber duck myself, I will try the forcing the TopAppBar to take more space than that the constraints passed to it by forcing it in a
layout {}
modifier as a first step.
a
What is the restriction requiring the inner Column take up the entire height even if it isn't necessary to scroll?
s
I want the screen to have a bottom attached button if that makes sense. The content has something at the top, and a button at the bottom of the screen, with empty space at the middle. But if the middle content is long enough that it warrants scrolling, then I want to allow that too, to reach that button at the bottom.
a
I see, and that bottom attached button is in
Stuff()
? What happens if you put a
Spacer
with
weight(1f)
inside the inner
Column
, instead of on the inner
Column
itself?
s
Nope, this brings back the problem of the inner column not taking up the entire height that it could. Here is a screenshot with and without the verticalScroll at the top level Column to show the different behavior. All this stems from the fact that the
verticalScroll
modifier makes the content wrap its height, which as I understand it needs to do in order to then know when it actually needs to scroll when the content doesn’t fit in the visible content.
a
Ah that is tricky, it’s a bit unfortunate that doesn’t work. You could put the
Spacer
s with weights outside the inner column, and maybe add a second inner column that also has the horizontal padding applied if needed.
Or you could pass the horizontal inset padding individually to all of the components that need it instead of having the inner
Column
s
Yeah but I’d really rather not do that for each of those items individually. But it’s always an option. Actually, heavily inspired by the latest Android Developers

videoā–¾

, with the one item being a rebel and not listening to what the parent says, I made the other solution of making the TopAppBar force get more width than what it is given by its parent šŸ˜„ So instead of opting into the padding on each component, opting out of the padding on the top app bar:
Copy code
@Composable
private fun TopAppBar(navigateBack: () -> Unit) {
  val horizontalPaddings = WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal).asPaddingValues()
  val layoutDirection = LocalLayoutDirection.current
  TopAppBarWithBack(
    ...,
    contentPadding = WindowInsets.safeDrawing
      .only(<http://WindowInsetsSides.Top|WindowInsetsSides.Top> + WindowInsetsSides.Horizontal)
      .asPaddingValues(),
    modifier = Modifier.layout { measurable, constraints ->
      val leftInsets = horizontalPaddings.calculateLeftPadding(layoutDirection).roundToPx()
      val rightInsets = horizontalPaddings.calculateRightPadding(layoutDirection).roundToPx()
      val requiredWidth = constraints.maxWidth + leftInsets + rightInsets
      val expandedConstraints = constraints.copy(
        minWidth = requiredWidth,
        maxWidth = requiredWidth,
      )
      val placeable = measurable.measure(expandedConstraints)
      // When going above the max size of parent, it gets centered, so we need to find the *real* 0 position of the parent here
      val actualZeroXPositionOfParent = (requiredWidth - constraints.maxWidth) / 2
      layout(placeable.width, placeable.height) {
        placeable.place(actualZeroXPositionOfParent - leftInsets, 0)
      }
    },
  )
}
This way my original column can stay as I originally wanted it to be, with fillMaxSize().verticalScroll().windowInsetsPadding(Horizontal), and then no inner column needed. Now I don’t know if I’d live to regret this, what do you think of it as an idea? (Also works fine with Ltr-Rtl it seems, which is a bonus 🤩)
a
Breaking the rules is always fun šŸ˜„ . Each way has a bit of a drawback, so I’d say go with the way that makes sense to you and your fellow devs or code reviewers in your project!