Android development / Intermediate: state, data, and inclusive features / Lesson 12
Accessible and adaptive feature design
Preserve the same reading task across window changes, assistive technologies, and non-touch input.
On this page
Lesson goals
- Adapt to current window constraints while preserving task state.
- Expose role, state, and actions through semantics.
Adapt the task, not only the dimensions
An adaptive reading app may show one destination on a compact window and list plus detail panes on a larger window. The selected item remains the same user task even when presentation changes. Use current window information rather than a permanent phone-versus-tablet flag, because desktop windows, split screen, folding, and rotation can change available space. Keep selection and draft ownership outside the presentation branch. Resizing should not silently reset the chosen item, lose a form, or start an unrelated navigation history.
Keep presentation decisions explicit
A small policy function can turn a measured or library-provided window category into a presentation choice. Production code should use the adaptive APIs and thresholds appropriate to its chosen library version rather than copying an arbitrary device width. The example receives an already-decided expanded flag to isolate the UI responsibility. Both branches receive the same selection and event callbacks. If a pane disappears, move focus to a meaningful remaining element and preserve a way to reach the hidden content rather than leaving keyboard users stranded.
@Composable
fun AdaptiveShelf(expanded: Boolean, selectedId: String?, onSelect: (String) -> Unit) {
if (expanded) {
Row(Modifier.fillMaxSize()) {
Box(Modifier.weight(1f)) { ShelfList(selectedId, onSelect) }
Box(Modifier.weight(2f)) { ShelfDetail(selectedId) }
}
} else {
CompactShelf(selectedId = selectedId, onSelect = onSelect)
}
}
ShelfList, ShelfDetail, and CompactShelf are app components. Compute expanded using the project’s window/adaptive integration. The compact component must provide a route between list and detail; this excerpt demonstrates shared ownership rather than implementing navigation.
Describe the control’s current meaning
A control needs a discoverable action and a perceivable state. Standard checkboxes, switches, buttons, and selection components already encode much of this information. For a custom combined row, avoid creating a clickable parent and an independently clickable child that perform the same action twice. Merge semantics only when the row should be one unit, and preserve separately actionable descendants when users need them. Use localized state descriptions when the default checked meaning does not match the product, and do not append redundant control-type words to every label.
@Composable
fun FinishedControl(finished: Boolean, onFinishedChange: (Boolean) -> Unit) {
Row(
Modifier.fillMaxWidth().toggleable(
value = finished,
role = Role.Checkbox,
onValueChange = onFinishedChange
).padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(checked = finished, onCheckedChange = null)
Text(stringResource(R.string.finished_reading))
}
}
Import foundation toggleable, Role, layout, and Material APIs; add finished_reading to localized resources. The checkbox has no separate callback because the parent handles the action, avoiding duplicate interactive targets for the same state. Verify the resulting merged semantics in the actual app.
Support more than a touch gesture
Swipe-only actions exclude users who cannot perform that gesture. Offer an explicit accessible action or menu alternative for archiving and reordering. Maintain a logical focus order, visible focus indication, and keyboard activation. Announce important validation or completion feedback without flooding users with repeated live-region updates on every keystroke. Never encode a required distinction through color alone. If motion is decorative, respect system preferences and avoid making animation the only signal that a task succeeded. Test the task with actual interaction rather than reviewing static screenshots alone.
Validate combinations that change behavior
Use a deliberate matrix: compact and expanded windows, enlarged fonts, Arabic and English, screen reader, keyboard, and disabled optional capabilities. These dimensions interact; a large font in a narrow Arabic window can expose a problem absent from each isolated preview. Check reading order after layout transitions and ensure error messages remain near the relevant field. Automated semantic assertions can protect roles and states, while manual assistive-technology testing evaluates whether the journey makes sense. Record concrete defects and expected behavior so accessibility work remains testable instead of a vague visual preference.
Common errors and fixes
Selection disappears when the window expands
- Why it happens
- Each layout branch owns a separate selected id.
- How to fix it
- Hoist task state above the adaptive branch.
- Prevent it next time
- Test resizing during an unfinished task.
A toggle is announced twice
- Why it happens
- Parent and child expose duplicate actions.
- How to fix it
- Give one node the action and verify merged semantics.
- Prevent it next time
- Traverse custom controls with a screen reader.
Archiving is impossible without swiping
- Why it happens
- The gesture has no equivalent accessible action.
- How to fix it
- Add a discoverable menu or semantic action.
- Prevent it next time
- Review every gesture for an alternative input path.
Check your understanding
1. A list-detail screen expands while a title draft is open. Specify what should persist and where focus should go.
Show worked solution
Preserve the selected id and draft in their shared task owner. Keep focus in the editor if that node remains meaningful; otherwise move it to the corresponding editor in the new presentation with a clear reading order. Do not reset the record merely because a second pane becomes visible.
2. An error is shown only as a red border around the title. Design a stronger contract and a verification.
Show worked solution
Add a localized explanatory message and appropriate error semantics associated with the field. Keep the text visible under font scaling and announce it through the normal accessibility path. Verify a user can locate the error, understand the correction, edit the field, and confirm the error clears using keyboard and screen reader.
Key takeaways
- Task state should survive changes in presentation.
- Semantics expose the same meaning as the visual control.
- Inclusive verification combines automation with real task traversal.