Course outline

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.

About 4 min readContent reviewed
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.

kotlin Two presentations share the same task state
@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.

kotlin One row owns the toggle action
@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.

Official references