Skip to content

Say a list item's text when a swipe scrolls it into view - #99

Merged
trypsynth merged 3 commits into
trypsynth:masterfrom
aaron-gh:offscreen-row-speech
Oct 7, 2026
Merged

trypsynth merged 3 commits into
trypsynth:masterfrom
aaron-gh:offscreen-row-speech

Conversation

@aaron-gh

@aaron-gh aaron-gh commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

When a swipe moves to a list item that is only partly on screen, the list scrolls it into view. But since #42, Backtalk works out what to say as soon as it sets focus, which is before the list has scrolled. The item's text was in children still past the edge of the list, and descriptions leave out off-screen children, so only the item's place in the list was said. For example, item 20 in Individual sounds and vibrations was just "20 of 80". The announcement prepared ahead for the next swipe (#43) had the same problem.

By default, such an item is now spoken from the app's focus event, which comes after the scroll, as in TalkBack, and nothing is prepared ahead for it. All other swipes still get the faster speech.

A new switch, Advanced settings > Reduce delay > Speak items before they scroll into view, speaks these items straight away instead. When Backtalk describes the item a swipe is moving to, children that are off screen only because of where they are count as on screen, since they will be once the list has scrolled. Android clamps each node's bounds on screen to every parent's, so a child wholly past the edge of the list comes out with inside-out bounds, its top below its bottom. A child that is hidden, or shrunk to nothing, keeps bounds the right way round, so it is still left out. An earlier version counted any empty bounds, which read a zero-size, unlabeled button in each notification in the shade as "Button".

Why it's off by default: an app that follows Android's conventions hides views it doesn't show, and lets its lists scroll a whole item into view. Such apps work correctly with this switch on. But not every app follows them, and the switch is off by default to protect users from those that don't. With it on, in such an app:

  • a part that the app keeps out of sight by moving it outside its item, instead of hiding it, is read even though it isn't shown
  • if the list can't scroll the whole item into view, the parts that stay off screen are read too

Neither changes where focus goes, only what is said.

Limitations: with the switch off, swipes that scroll an item into view are as slow as they were before #42.

A swipe onto a list item that is only partly on screen scrolls it into
view, but Backtalk worked out what to say before the list had scrolled.
The item's text was in children still past the edge of the list, which
descriptions leave out, so only its place in the list was said, such as
"20 of 80" in Individual sounds and vibrations. The announcement
prepared for the next swipe had the same problem.

By default, such an item is now spoken from the app's focus event,
which comes after the scroll, as in TalkBack, and nothing is prepared
for it.

A new switch, Advanced settings > Reduce delay > Speak items before
they scroll into view, off by default, speaks them straight away
instead. Children that are off screen only because of where they are
then count as on screen, since they will be once the swipe has
scrolled. Their bounds on screen are clipped to their parents, so they
are empty, unlike those of children that are on screen but hidden.

Limitations: with the switch off, these swipes are as slow as before
trypsynth#42. With it on, a child that the app shrinks to nothing instead of
hiding is read, and so is one that stays off screen when the list
cannot scroll the whole item into view.
With Speak items before they scroll into view on, notifications in the
shade were spoken as "Button", or with "Button" first: a small
unlabeled button in each was not shown and had no size, and empty
bounds counted as being past the edge of the list.

A child's bounds on screen are clamped to each parent's, so a child
wholly past the edge of a list has bounds that are inside out, with the
top below the bottom. A child shrunk to nothing has its top and bottom
equal. Only inside-out bounds now count. The bounds of the children of
a swipe's target are also logged.
Parts shrunk to nothing are no longer read. What remains is a part
that an app keeps out of sight by moving it outside its item.
@trypsynth
trypsynth merged commit ef77511 into trypsynth:master Oct 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants