Compose Layout, Lists & Modifiers Quiz
UI › Compose UI
You write Box(Modifier.size(100.dp).background(Color.Blue).padding(20.dp)) wrapping a Text. What does the blue region look like?
- Only the 20.dp padding ring is blue, while the center stays clear
- The whole 100.dp box is blue, and the Text is inset by 20.dp
- Nothing is blue because background has to be applied last here
- The Text itself turns blue, but the surrounding box stays clear
Answer: The whole 100.dp box is blue, and the Text is inset by 20.dp
background is applied before padding here, so the whole 100.dp area is painted blue and the padding then insets the Text within that blue region.
In a horizontally heterogeneous LazyColumn (headers and rows), what does adding contentType to items() primarily improve?
- It sorts items by type before they are shown in the list
- It guarantees item state survives after the app is killed
- It animates transitions when one item type changes to another
- It lets Compose reuse compositions only within the same type
Answer: It lets Compose reuse compositions only within the same type
contentType scopes composition reuse to matching types so a scrolled-off header isn't reused as a row, making recycling in mixed lists more efficient.
Which statement about Modifier.weight(1f) is correct?
- It only compiles as a direct child of a Row or Column
- It works on any composable placed directly inside a Box
- It assigns the child a fixed, absolute width in pixels
- It behaves just like calling fillMaxWidth() on each child
Answer: It only compiles as a direct child of a Row or Column
weight is defined on RowScope and ColumnScope, so it's scope-restricted to direct children of a Row or Column and proportionally divides the remaining space.
A list scrolls back to the top and loses each row's expanded/collapsed state after the data list is reordered. What is the most likely cause?
- contentPadding wasn't set on the LazyColumn, causing the reset
- The items had no stable key, so Compose couldn't track identity
- verticalArrangement.spacedBy was missing, so state got shuffled
- The list should have used LazyRow instead of a vertical layout
Answer: The items had no stable key, so Compose couldn't track identity
Without stable keys, Compose falls back to positional identity, so reordering reassigns remembered state to the wrong items and resets it. Stable keys preserve per-item state across data changes.
What is the difference between Modifier.size(100.dp) and Modifier.requiredSize(100.dp)?
- Both always ignore the parent, so there’s no real difference here
- size forces 100.dp, while requiredSize is just a soft suggestion
- requiredSize only works inside a Box or other container layout
- size obeys parent constraints; requiredSize forces the 100.dp anyway
Answer: size obeys parent constraints; requiredSize forces the 100.dp anyway
size proposes a measurement that the parent's constraints can still clamp, whereas requiredSize ignores those constraints and forces the exact dimension, potentially overflowing the parent.
Why does putting a LazyColumn directly inside a Column(Modifier.verticalScroll(...)) throw at runtime?
- The scrolling parent offers infinite height, so the list can't measure
- A LazyColumn is simply never permitted as a direct child of any Column
- verticalScroll has been deprecated in current Compose releases
- Two scroll states can't be remembered within a single composition
Answer: The scrolling parent offers infinite height, so the list can't measure
A vertically scrolling Column offers unbounded height, leaving the LazyColumn with no finite viewport to size against, which throws an IllegalStateException. Flatten to one LazyColumn or bound the inner height.
You want to pass the current theme's spacing to many nested composables without adding parameters to each. Which tool fits best?
- A top-level global mutable variable shared across the app
- Modifier.weight passed along to every nested composable
- A CompositionLocal used with CompositionLocalProvider
- BoxWithConstraints wrapped around the entire composable tree
Answer: A CompositionLocal used with CompositionLocalProvider
CompositionLocal provides a value implicitly down the composition tree via CompositionLocalProvider, letting descendants read it with .current without prop-drilling through every layer.
A Box uses contentAlignment = Alignment.Center for most children, but one badge child must sit in the top-end corner instead. How do you override alignment for just that child?
- Wrap that child in its own nested Box and set its contentAlignment
- Set verticalAlignment on the parent Box
- Apply Modifier.align(Alignment.TopEnd) to that child
- Use Modifier.weight on the child
Answer: Apply Modifier.align(Alignment.TopEnd) to that child
BoxScope exposes Modifier.align, which lets an individual child override the Box's contentAlignment, so the badge can be placed at TopEnd while siblings stay centered.
When the value supplied to a staticCompositionLocalOf changes at the provider, what recomposes?
- The whole CompositionLocalProvider subtree, even if it never reads it
- Only composables that read the local through .current are recomposed
- Nothing changes, because a static CompositionLocal value cannot update
- Only the provider’s nearest direct child is recomposed when it changes
Answer: The whole CompositionLocalProvider subtree, even if it never reads it
staticCompositionLocalOf does not track individual reads, so any change forces the whole provided subtree to recompose; compositionLocalOf instead tracks reads and recomposes only the readers.
Inside a Box whose size is determined by its largest child, you add a background layer that should exactly match the Box's final measured size without affecting how that size is computed. Which modifier fits?
- Modifier.fillMaxSize()
- Modifier.size(IntrinsicSize.Max)
- Modifier.weight(1f)
- Modifier.matchParentSize()
Answer: Modifier.matchParentSize()
BoxScope.matchParentSize sizes the child to the Box's resolved size but is excluded when the Box measures itself, so it never grows the Box; fillMaxSize fills incoming max constraints and does participate in sizing.
Your LazyColumn rows use Modifier.animateItem(), but nothing animates when the underlying list is reordered. What is the most likely fix?
- Wrap each item in AnimatedVisibility for reordering effects
- Provide a stable key in items() so Compose tracks identity
- Replace items() with a manual for-loop inside the lambda
- Add a contentType to every item so moves are detected
Answer: Provide a stable key in items() so Compose tracks identity
animateItem only animates moves, insertions, and removals when items have stable keys; without keys Compose uses positional identity and cannot tell that an item moved.
On a Text, how does Modifier.clickable{}.padding(16.dp) differ from Modifier.padding(16.dp).clickable{}?
- Modifier order is irrelevant here, so the two arrangements behave identically
- padding must always come after clickable, otherwise it throws at runtime
- clickable-first ripples over the padding; padding-first clicks only the content
- Only the padding-before-clickable ordering ever produces a visible ripple
Answer: clickable-first ripples over the padding; padding-first clicks only the content
Modifiers apply outside-in, so a clickable placed before padding extends the touch target and ripple across the padded region, while padding placed first shrinks the clickable area down to the content.
You want a uniform 8.dp gap between every child of a Column, with no extra space above the first child or below the last. What is the cleanest approach?
- Column(verticalArrangement = Arrangement.spacedBy(8.dp))
- Add Modifier.padding(vertical = 8.dp) to each child item
- Place Spacer(Modifier.weight(1f)) between each pair of children
- Set contentPadding = 8.dp on the Column to add the gaps
Answer: Column(verticalArrangement = Arrangement.spacedBy(8.dp))
Arrangement.spacedBy inserts the gap only between adjacent children and not at the outer edges; per-child vertical padding would also add space at the top and bottom and double up between items, and Column has no contentPadding parameter.
In a Row containing two Texts, you want a vertical Divider between them to be exactly as tall as the taller Text. Which approach works in Compose's single-pass layout?
- Hardcode the divider height in dp to match the taller Text
- Apply Modifier.fillMaxHeight() to the divider on its own
- Wrap the entire Row in a BoxWithConstraints measuring layout
- Give the Row height(IntrinsicSize.Min), then fillMaxHeight the divider
Answer: Give the Row height(IntrinsicSize.Min), then fillMaxHeight the divider
IntrinsicSize.Min makes the Row pre-query its children's intrinsic heights so the Row's height resolves to the taller Text, letting the divider's fillMaxHeight fill that height; fillMaxHeight by itself has no fixed height to fill in an otherwise wrap-height Row.