Adaptive Layouts & Accessibility: learning goals
Build a planner that stays usable when its window shrinks, text grows, or a student uses a screen reader. Layout decisions should respond to the space available to the app and preserve the same user task.
Project setup and scope
Build the mental model
A tablet can have a narrow split-screen window, and a phone in landscape can have very little vertical room. A permanent isTablet flag cannot describe either situation. Begin with a compact single-column layout, then add a two-pane arrangement only when both content and available space justify it.
Adaptive UI changes arrangement while retaining identity and user intent. Resizing should not silently clear a selected session or create a second independent copy of form state. Hoist state above the layout branches and pass the same values and callbacks to each arrangement.
Accessibility includes meaning and interaction as well as appearance. Material controls already expose roles and state; custom drawings and interactions need equivalent semantics. Use text labels for actions, meaningful descriptions for informative images, null descriptions for decorative images, and sufficient touch space. Test with TalkBack rather than assuming a visible label is announced correctly.
Text uses sp so user font settings can affect it. Fixed-height containers can clip enlarged labels. Allow wrapping, avoid unnecessary hard height constraints, and test the longest meaningful translations as well as your shortest sample text. Contrast and selected states should be understandable without relying on color alone.
Choose the right approach
| Need | Approach |
|---|---|
| Local card width | BoxWithConstraints can adapt a reusable component to its parent's actual constraints. |
| Whole app panes/navigation | Use window size classes/adaptive scaffolds; include height and fold posture where relevant. |
| Standard button or switch | Prefer Material controls and their existing semantics/touch behavior. |
| Custom chart | Expose a concise text summary and progress semantics; color alone cannot convey meaning. |
Predict and trace the behavior
Adaptive Layouts & Accessibility
Predict what happens next. Follow the diagram, then explain the change in your own words.
Constraints down · sizes up
width: 120…280 dp200 × 56 dpA size within the constraintsIllustrative dp values; real constraints are measured in pixels.
A child chooses a legal size, then the parent places it. Measurement and placement are separate responsibilities.
Explore this general model independently. The lesson sequence below follows its own example.
Constraints: A parent sends minimum and maximum width and height constraints to its child.
Read available space
The containing layout provides current constraints. Device category does not determine the app window.
Worked Kotlin example
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun AdaptivePlanner(
summary: @Composable () -> Unit,
sessions: @Composable () -> Unit,
modifier: Modifier = Modifier,
) {
BoxWithConstraints(modifier.fillMaxWidth()) {
// Component policy, not a universal device breakpoint.
if (maxWidth >= 720.dp) {
Row(horizontalArrangement = Arrangement.spacedBy(24.dp)) {
Column(Modifier.weight(1f)) { summary() }
Column(Modifier.weight(2f)) { sessions() }
}
} else {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
summary()
sessions()
}
}
}
}
// Example content: AdaptivePlanner(summary = { Text("2 sessions") },
// sessions = { Text("Compose state — planned") })- The two content slots are stateless. Put session data and form inputs in a caller above AdaptivePlanner.
- 720 dp is a deliberate component policy chosen for this example's content, not a replacement definition of Android window size classes. Test near both sides of it.
- A lazy list placed in a scrolling parent still needs valid height constraints. In a full-screen planner, give the list a bounded area and apply Scaffold insets at the appropriate boundary.
Student practice and expected behavior
Adapt the Phase 2 planner to two arrangements. Add a labeled completion control and a text summary of completion. Keep the selected filter identical while resizing.
- At compact width the form and sessions are stacked; at a useful wider width they occupy separate panes.
- At 200% font scale, controls remain reachable and important labels are readable without clipping.
- TalkBack announces each action and current completion state once, in a logical order.
- Resizing and rotating preserve explicitly saved small inputs; list durability remains the responsibility of the later data layer.
Write down the input, expected outcome and observed outcome for each check. Include a screenshot, a short recording or a nonpersonal diagnostic trace appropriate to the behavior you are proving.
Debugging clinic
- Calling both screen width and local component width 'the available width' can hide the source of a bad breakpoint. Inspect the actual parent constraints.
- Adding contentDescription to every Text can create duplicate announcements; standard Text already has text semantics.
- A visually small icon can be used inside a sufficiently large IconButton. Shrinking the whole interactive control makes it hard to activate.
- Do not fix clipping by disabling font scaling or preventing resizing. Repair layout constraints and reachability.
Instructor prompts
- Give one team a compact window and another a large-font layout; have them complete the same task and compare failures.
- Ask students to point to the single owner of a filter that survives an arrangement change.
- Turn off the display or look away during a TalkBack demonstration. Ask which labels convey an action rather than an icon's shape.
Teach-back checkpoint
Quick check and references
Quick check
1. What should select the app's high-level layout?
2. Which is the best first choice for a normal completion toggle?
Continue with the phase capstone after demonstrating the practice checks. Use the official documentation to verify APIs against your project's selected dependency versions.