Repository navigation
implicit a11y scrolling broken with pinned & floating AppBar #35488
Copy link
Copy link
Labels
a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)Accessibility, e.g. VoiceOver or TalkBack. (aka a11y)f: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.
Milestone
Description
- Run the following code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('Hello'),
pinned: true,
floating: true,
expandedHeight: 200.0,
),
SliverFixedExtentList(
itemExtent: 100.0,
delegate: SliverChildBuilderDelegate(
(BuildContext c, int index) {
return Container(
height: 100.0,
color: index % 2 == 0 ? Colors.red : Colors.yellow,
child: Text('Tile $index'),
);
},
),
),
],
),
);
}
}- Scroll down a bit
- turn on talkback
- focus on an item in the list
- swipe left a couple of times
Expected behavior:
When the a11y focus reaches an item that's partially visible, it should be brought fully on screen. When moving a11y focus to the next off-screen item, the list should scroll and a11y focus should move to the next item
Observed behavior:
Partially visible items are not brought on screen. When moving focus to an offscreen item it moves to the AppBar and the list scrolls all the way to the top.
It looks like the semantics tree is already incorrect:
I/flutter ( 8037): SemanticsNode#0
I/flutter ( 8037): │ Rect.fromLTRB(0.0, 0.0, 1440.0, 2392.0)
I/flutter ( 8037): │
I/flutter ( 8037): └─SemanticsNode#1
I/flutter ( 8037): │ Rect.fromLTRB(0.0, 0.0, 411.4, 683.4) scaled by 3.5x
I/flutter ( 8037): │ textDirection: ltr
I/flutter ( 8037): │
I/flutter ( 8037): └─SemanticsNode#2
I/flutter ( 8037): │ Rect.fromLTRB(0.0, 0.0, 411.4, 683.4)
I/flutter ( 8037): │ flags: scopesRoute
I/flutter ( 8037): │
I/flutter ( 8037): ├─SemanticsNode#3
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 0.0, 411.4, 683.4)
I/flutter ( 8037): │ │
I/flutter ( 8037): │ └─SemanticsNode#14
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 0.0, 411.4, 683.4)
I/flutter ( 8037): │ │ actions: scrollDown, scrollUp
I/flutter ( 8037): │ │ flags: hasImplicitScrolling
I/flutter ( 8037): │ │ scrollIndex: 23
I/flutter ( 8037): │ │ scrollExtentMin: 0.0
I/flutter ( 8037): │ │ scrollPosition: 2500.0
I/flutter ( 8037): │ │ scrollExtentMax: Infinity
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#137
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, -250.0, 411.4, -176.0)
I/flutter ( 8037): │ │ flags: isHidden
I/flutter ( 8037): │ │ HIDDEN
I/flutter ( 8037): │ │ label: "Tile 20"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#138
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, -176.0, 411.4, -76.0)
I/flutter ( 8037): │ │ flags: isHidden
I/flutter ( 8037): │ │ HIDDEN
I/flutter ( 8037): │ │ label: "Tile 21"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#139
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, -76.0, 411.4, 24.0)
I/flutter ( 8037): │ │ flags: isHidden
I/flutter ( 8037): │ │ HIDDEN
I/flutter ( 8037): │ │ label: "Tile 22"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#12
I/flutter ( 8037): │ │ │ Rect.fromLTRB(0.0, 0.0, 411.4, 80.0)
I/flutter ( 8037): │ │ │
I/flutter ( 8037): │ │ └─SemanticsNode#13
I/flutter ( 8037): │ │ Rect.fromLTRB(16.0, 40.5, 63.0, 63.5)
I/flutter ( 8037): │ │ flags: isHeader, namesRoute
I/flutter ( 8037): │ │ label: "Hello"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#140
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 80.0, 411.4, 124.0)
I/flutter ( 8037): │ │ label: "Tile 23"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#141
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 124.0, 411.4, 224.0)
I/flutter ( 8037): │ │ label: "Tile 24"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#142
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 224.0, 411.4, 324.0)
I/flutter ( 8037): │ │ label: "Tile 25"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#143
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 324.0, 411.4, 424.0)
I/flutter ( 8037): │ │ label: "Tile 26"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#144
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 424.0, 411.4, 524.0)
I/flutter ( 8037): │ │ label: "Tile 27"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#145
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 524.0, 411.4, 624.0)
I/flutter ( 8037): │ │ label: "Tile 28"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#146
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 624.0, 411.4, 683.4)
I/flutter ( 8037): │ │ label: "Tile 29"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#147
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 724.0, 411.4, 824.0)
I/flutter ( 8037): │ │ flags: isHidden
I/flutter ( 8037): │ │ HIDDEN
I/flutter ( 8037): │ │ label: "Tile 30"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ ├─SemanticsNode#148
I/flutter ( 8037): │ │ Rect.fromLTRB(0.0, 824.0, 411.4, 924.0)
I/flutter ( 8037): │ │ flags: isHidden
I/flutter ( 8037): │ │ HIDDEN
I/flutter ( 8037): │ │ label: "Tile 31"
I/flutter ( 8037): │ │ textDirection: ltr
I/flutter ( 8037): │ │
I/flutter ( 8037): │ └─SemanticsNode#149
I/flutter ( 8037): │ Rect.fromLTRB(0.0, 924.0, 411.4, 933.4)
I/flutter ( 8037): │ flags: isHidden
I/flutter ( 8037): │ HIDDEN
I/flutter ( 8037): │ label: "Tile 32"
I/flutter ( 8037): │ textDirection: ltr
I/flutter ( 8037): │
I/flutter ( 8037): └─SemanticsNode#15
I/flutter ( 8037): │ merge boundary ⛔️
I/flutter ( 8037): │ Rect.fromLTRB(0.0, 0.0, 56.0, 56.0) with transform
I/flutter ( 8037): │ [1.0,2.4492935982947064e-16,0.0,339.42857142857144;
I/flutter ( 8037): │ -2.4492935982947064e-16,1.0,0.0,611.4285714285714;
I/flutter ( 8037): │ 0.0,0.0,1.0,0.0; 0.0,0.0,0.0,1.0]
I/flutter ( 8037): │ label: "Increment"
I/flutter ( 8037): │ textDirection: ltr
I/flutter ( 8037): │
I/flutter ( 8037): └─SemanticsNode#16
I/flutter ( 8037): merged up ⬆️
I/flutter ( 8037): Rect.fromLTRB(0.0, 0.0, 56.0, 56.0)
I/flutter ( 8037): actions: tap
I/flutter ( 8037): flags: isButton, hasEnabledState, isEnabled
I/flutter ( 8037): thickness: 6.0
I/flutter ( 8037):
The app bar nod (label: "Hallo") shouldn't be in the middle of all the tiles within the scrollable node.
This reproduces on Android, still investigating if iOS is also affected.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)Accessibility, e.g. VoiceOver or TalkBack. (aka a11y)f: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.
Activity
goderbauer commentedon Jul 2, 2019
iOS is also affected. It is probably the incorrectly generated a11y tree that's causing this.
goderbauer commentedon Jul 2, 2019
/cc @dnfield
goderbauer commentedon Jul 2, 2019
Little more debugging: This line sets excludeFromScrolling to false even though it should be true for everything to work correctly:
flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart
Line 480 in 3a67442
dnfield commentedon Jul 4, 2019
So at the commit where you added that, things worked. Unfortunately it's a little tricky to get things to build at that commit now.
A big difference that i'm seeing is that at that commit, for a floating app bar to be pinned, it had to have a bottom set. That seems to no longer be the case.
dnfield commentedon Jul 4, 2019
Actually that makes sense - the problem now is that
overlapsContentends up being false all the time. I think that's our bug.dnfield commentedon Jul 4, 2019
Archaeology: 76baa5e removed the assert.
Once you get rid of a
bottomperferred size widget, the overlaps content logic doesn't work anymore.dnfield commentedon Jul 16, 2019
Reopening since this is being reverted
github-actions commentedon Aug 29, 2021
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 -vand a minimal reproduction of the issue.