androidaccessibilitysemanticstalkback

How to make talkback read out Text and switch together in Android?


Hello I am trying to make talkback read out text from Text() and default line from Switch() using compose semantics. This is my code:

var toggle by remember {
                mutableStateOf(true)
            }
            Column(
                modifier = Modifier.fillMaxSize(),
            ) {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .wrapContentHeight()
                        .semantics(mergeDescendants = true) {
                            isTraversalGroup = true
                        },
                ) {
                    Text(
                        modifier = Modifier.semantics {
                            traversalIndex = 1f
                        },
                        text = "Show my name.",
                    )
                    Switch(
                        modifier = Modifier.semantics {
                            traversalIndex = 2f
                        },
                        checked = toggle,
                        onCheckedChange = { toggle = !toggle },
                    )
                }
            }

For some reason only the Text gets read out and the default line of switch is ignored. My goal is to have it read like "Show my name. On/Off switch double tap to toggle". In one go. How can I achieve this?


Solution

  • According to the documentation:

    When implementing selection controls like Switch, RadioButton, or Checkbox, you typically lift the clickable behavior to a parent container, set the click callback on the composable to null, and add a toggleable or selectable modifier to the parent composable.

    So using the toggleable modifier on the row in your case would look something like:

        var toggle by remember {
            mutableStateOf(true)
        }
        Column(
            modifier = Modifier.fillMaxSize(),
        ) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
                    .toggleable(
                        value = toggle,
                        role = Role.Switch,
                        onValueChange = { toggle = !toggle }
                    )
            ) {
                Text(
                    text = "Show my name.",
                    modifier = Modifier
                        .weight(1f)
                        .align(Alignment.CenterVertically)
                )
                Switch(
                    checked = toggle,
                    onCheckedChange = null,
                )
            }
        }
    

    I tried it with basic keyboard functions as well and it seems to work:

    adb shell input keyevent KEYCODE_TAB    # navigate
    adb shell input keyevent KEYCODE_ENTER  # toggle
    

    If the order of the announcement concerns you ('On, [Text], Switch'), please be aware that this can be modified by user settings of TalkBack and is a result of the calculations on the screen reader (TalkBack).

    A test android app with three elements in a column, a text view with 'element 1', the element in question, a text view with a switch, and a third text view with 'element 3.' The screen read goes to the switch row which reads 'On, Show My Name, Switch.' and when toggled, it goes 'Off'