So I'm working on the Accessibility feature in my app.
My problem is, the TalkBack announces extra texts regardless of the clearAndSetSemantics{} fun.
For example to the close button it says: "Close button content desctiption, button Out of list" instead of "Close button content desctiption, button" or for every star it announces: "1 Rating icon item double tap to activate" instead of "1 Rating icon item".
You can reproduce the issue with this code:
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun Example(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth()
.semantics {
isTraversalGroup = true
}
.background(Color.White)
) {
IconButton(
modifier = Modifier
.clearAndSetSemantics {
contentDescription = "Close button content desctiption, button"
testTag = "closeButtonTextTag"
},
onClick = {}
) {
Icon(
Icons.Default.Close,
contentDescription = ""
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Text one description")
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Text two description")
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Absolute.SpaceEvenly
) {
for (ratingIndex in 1..5) {
Column(
modifier = Modifier.weight(1f)
) {
Icon(
modifier = Modifier
.size(30.dp)
.align(Alignment.CenterHorizontally)
.clickable {
}
.clearAndSetSemantics {
contentDescription = "$ratingIndex Rating icon item"
testTag = "ratingIconTestTag"
},
imageVector = if (ratingIndex < 3) {
Icons.Default.Star
} else {
Icons.Filled.Star
},
contentDescription = "",
tint = Color.Unspecified
)
Text(
modifier = Modifier
.padding(vertical = 8.dp)
.semantics {
invisibleToUser()
testTag = "textTestTag"
},
text = "Last text string"
)
}
}
}
}
}
@Preview
@Composable
fun ExamplePreview() {
Example(Modifier.background(Color.White))
}
If I put the clearAndSetSemantics{} block to the Rating star column it works fine, but in this case the whole column get accessibility focus instead of the icon.
What am I missing ? Or it works as expected?
I don't think it is the best solution, but in my case it worked. So I simple put the Icon into a Box, and defined the semantics on the Box.
The clearAndSetSemantics
fun Clears the semantics of all the descendant nodes and sets new semantics.
Box(
modifier = modifier
.padding(
start = CloseButtonStartPadding,
top = CloseButtonTopPadding
)
.clearAndSetSemantics {
contentDescription = closeButtonContentDescription
testTag = closeButtonTextTag
}
) {
IconButton(
onClick = onButtonClick
) {
Icon(
)
}
}