Skip to content

When moving accessibility focus off-screen, scroll the screen. #1714

Closed

Description

@Hixie
No description provided.

Activity

  1. added
    c: new featureNothing broken; request for a new capability
    frameworkflutter/packages/flutter repository. See also f: labels.
    a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)
    on Feb 9, 2016
  2. added this to the milestone on Feb 9, 2016
  3. modified the milestones: , on Sep 16, 2016
  4. modified the milestones: 2: Make Early Adopters happy, on Jan 26, 2017
  5. Hixie commented on Jun 26, 2017

    @Hixie
    ContributorAuthor

    Simplest way to fix this is probably to keep one item before and after the currently visible items in a lazy list alive even though they're off-screen, and to then autoscroll when accessibility focus is moved to those items.

    This would also fix #170.

  6. goderbauer commented on Jul 10, 2017

    @goderbauer
    Member

    flutter-team-archive/engine#3856 addressed this on Android for simple lists containing just one Sliver.

    Lists with multiple slivers don't behave correctly when switching from one sliver to another. In order to fix this, we need to expose each sliver individually as a "android.widget.ScrollView" to Android's accessibility API and we also need to know if a sliver has hidden elements beyond its trailing and leading edge. The sliver is only allowed to claim to be scrollable in a particular direction if elements can be exposed when scrolling in that direction (#1675).

  7. Hixie commented on Jul 10, 2017

    @Hixie
    ContributorAuthor

    Exposing the slivers doesn't seem right to me, unless I misunderstood what you meant. e.g. a SliverPadding containing a SliverList should presumably act exactly the same as a SliverList alone; a viewport with ten SliverToBoxAdapters should presumably act the same as a viewport with five two-item SliverLists which should act the same as a single ten-item SliverList.

  8. goderbauer commented on Jul 11, 2017

    @goderbauer
    Member

    Those are the trivial cases that should behave exactly as you say. However, it gets more complicated: Let's imagine we have a pinned SliverAppBar and a SliverList:

    new CustomScrollView(
      slivers: <Widget>[
        new SliverAppBar(
          expandedHeight: 150.0,
          pinned: true,
          flexibleSpace: const FlexibleSpaceBar(
            title: const Text('Available seats'),
          ),
        ),
        new SliverList(
          delegate: new SliverChildListDelegate(
            new List<int>.generate(10, (int i) => i + 1)
                .map((int i) => new MergeSemantics(
                      child: new ListTile(
                        leading: const Icon(Icons.event_seat),
                        title: new Text('The seat for $i'),
                      ),
                    )).toList(),
          ),
        ),
      ],
    )

    Let's imagine we are scrolled all the way to the bottom of the list (app bar is at its smallest hight), that leaves us with the following semantics tree:

    I/flutter (12529):      └SemanticsNode(3; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4) (clipped); SemanticsAction.scrollLeft; SemanticsAction.scrollRight; SemanticsAction.scrollUp; SemanticsAction.scrollDown)
    I/flutter (12529):        ├SemanticsNode(4; Rect.fromLTRB(72.0, 40.0, 209.0, 64.0) (clipped); "Available seats")
    I/flutter (12529):        ├SemanticsNode(12 (leaf merge); Rect.fromLTRB(0.0, 128.5, 411.4, 184.5) (clipped); "The seat for 8")
    I/flutter (12529):        ├SemanticsNode(13 (leaf merge); Rect.fromLTRB(0.0, 184.5, 411.4, 240.5) (clipped); "The seat for 9")
    I/flutter (12529):        ├SemanticsNode(14 (leaf merge); Rect.fromLTRB(0.0, 240.5, 411.4, 296.5) (clipped); "The seat for 10")
    

    If you now swipe through all accessibility nodes starting at the bottom, the accessibility focus will eventually switch from node 12 (last node in the ListSliver) to node 4 (the AppBarSliver) without doing a scroll. If you continue swiping through the nodes upwards of node 4, Android will realize that you're trying to leave a scrollable container and issue a scroll action which scrolls down the ListSliver. This behavior is not correct. Instead, the list should have scrolled when the accessibility focus moved away from node 12 (which is essentially the boundary between the two Slivers at play here). To achieve this, we will have to expose the sliver boundaries to the Android Accessibility API somehow (and Android's accessibility API also needs to be know if a given sliver is still scrollable or if it should move the accessibility focus on to the next sliver).

    That's what I meant by my previous comment.

  9. Hixie commented on Jul 11, 2017

    @Hixie
    ContributorAuthor

    Oh man, that's a tricky case. Good luck? :-)

  10. goderbauer commented on Sep 7, 2017

    @goderbauer
    Member

    This has been fixed in Android. I am going to open a separate bug for iOS.

  11. github-actions commented on Aug 17, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  12. locked as resolved and limited conversation to collaborators on Aug 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)c: new featureNothing broken; request for a new capabilityframeworkflutter/packages/flutter repository. See also f: labels.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions