Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Accessible Apps with Jetpack Compose

Building Accessible Apps with Jetpack Compose

Nowadays the accessibility starts to become required by law. We need to know how to overcome this

ThawZinToe

April 04, 2024
Tweet

More Decks by ThawZinToe

Other Decks in Technology

Transcript

  1. Why does it matter? It’s very important to do accessibility

    and then enforced by law in Europe Country 3
  2. Minimal Touch/ Pointer Target 4 • Minimal 48 x 48

    dp • minimumInteractiveComponentSize() modifier extension
  3. README.md 📐 Blueprint Visualize the dimensions of your composables on

    a blueprint dependencies { debugImplementation("com.github.popovanton0.blueprint:blueprint:1.0.0-alpha04") releaseImplementation("com.github.popovanton0.blueprint:blueprint-no-op:1.0.0-alpha04") } 5 popovanto0/ Blueprint code issue pull-request
  4. 9 Font Scale • @Preview (fontScale = 2f) • Modifier.verticalScroll(rememberScrollState)

    • maxLines = … • overflow = TextOverflow.Ellipsis • Or overflow = TextOverflow.Visible
  5. TextOverFlow 10 Text( modifier = Modifier.background(Color.Cyan).size(20.dp), text = "Visible", overflow

    = TextOverflow.Visible, ) Text( modifier = Modifier.size(20.dp).background(Color.Yellow), text = "Ellipsis", overflow = TextOverflow.Ellipsis, ) Text( modifier = Modifier.background(Color.Green).size(20.dp), text = "Clip", overflow = TextOverflow.Clip, ) Vi si bl e El. Cli
  6. Focus Order 11 To ensure that app is usable when

    the user navigates with such keystrokes, you have to check the focus order. Pressing the Tab or arrow keys should move the focus in a logical order. A focus can also move due to the IME (Input Method Editor) action on the on-screen keyboard.
  7. Focus Order 12 • Add focusRequester and focusProperties modifiers •

    Adding the Next IME action won’t add reactions to Enter and Tab keystrokes. • Alternatively, use the onPreviewKeyEvent
  8. Focus Order 13 val (firstNameField, lastNameField, emailField) = remember {

    FocusRequester.createRefs() } TextField( modifier = Modifier .focusRequester(firstNameField) .focusProperties { next = lastNameField }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), ) TextField( modifier = Modifier .focusRequester(lastNameField) .focusProperties { next = emailField }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), ) TextField( modifier = Modifier .focusRequester(emailField) .focusProperties { next = firstNameField }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), )
  9. IME Actions 15 TextField( keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send), keyboardActions

    = KeyboardActions( onSend = { // send the form to the server } ), onValueChange = {}, value = "First name", )
  10. TalkBack 16 • Drag, SIngle tap to move focus with

    Finger • Double tap to click! • Swipe right to move focus forward(left - backward) • Swipe down then right (L-shape) to show TalkBack menu • Many more gestures
  11. Switch 17 var isEnabled by remember {mutableStateOf(false)} Row( modifier =

    Modifier ) { Text(text = "Newsletter") Switch(checked=isNewsletterEnabled) }
  12. Accessible Switch 18 var isEnabled by remember {mutableStateOf(false)} Row( modifier

    = Modifier .toggleable( value = isNewsletterEnabled, onValueChange = {isEnabled = isChecked }, role = Role.Switch) ) { Switch(checked=isNewsletterEnabled) }
  13. Modifier.semantics 20 Modifier.semantics { stateDescription = if (isNewsletterEnabled) "Enabled" else

    "Disabled" onClick( label = "toggle newsletter subscription", action = null ) }
  14. Content description 21 Icon( imageVector = Icons.Filled.Check, contentDescription = "Access

    Granted" ) contentDescription = "" contentDescription = null Access granted, Image Unlabelled, Image Ignored by TalkBack
  15. Merging descendants 23 Row(modifier = Modifier){ Text(text = "Thaw") Spacer(Modifier.width(4.dp))

    Icon( imageVector = Icons.Default.Check, contentDescription = null ) } Row( modifier = Modifier .semantics(mergeDescendants = true) {} ) Materials Materials
  16. Custom Actions 24 .semantics { customActions = listOf( CustomAccessibilityAction( label

    = "Delete item", action = ::deleteItem ), CustomAccessibilityAction( label = "Archive item", action = ::archiveItem ) ) }
  17. Live Regions 25 TalkBack announces live region on change even

    if it is not focused Row( Modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite contentDescription = dateFormatter.format(date) } ) { Text(text = date) // Next and Previous Button Code } January 2023 February 2023
  18. Learn more about Accessibility 32 • Web content Accessibility guidelines

    • Android Accessibility by tutorials - droidcon • Universal Design Principles & Material Design Guidelines ◦ Equitable of use ◦ Flexibility of use ◦ Simple and Intuitive use ◦ Perceptible of information ◦ Fault tolerant ◦ Low physical effort ◦ Size and space for approach