diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index 7134a235ea..cf69e2dd37 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -147,7 +147,7 @@ class CupertinoNavigationBar extends StatelessWidget implements ObstructingPrefe child: new _CupertinoPersistentNavigationBar( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, - middle: middle, + middle: new Semantics(child: middle, header: true), trailing: trailing, actionsForegroundColor: actionsForegroundColor, ), @@ -491,7 +491,7 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate new _CupertinoPersistentNavigationBar( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, - middle: middle ?? title, + middle: new Semantics(child: middle ?? title, header: true), trailing: trailing, // If middle widget exists, always show it. Otherwise, show title // when collapsed. @@ -533,7 +533,10 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate child: new SafeArea( top: false, bottom: false, - child: title, + child: new Semantics( + header: true, + child: title, + ), ), ), ), diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 1b353ab7c7..ca472f3700 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -393,20 +393,24 @@ class _AppBarState extends State { Widget title = widget.title; if (title != null) { + bool namesRoute; switch (defaultTargetPlatform) { case TargetPlatform.android: case TargetPlatform.fuchsia: - title = new Semantics(namesRoute: true, child: title); + namesRoute = true; break; case TargetPlatform.iOS: break; } - title = new DefaultTextStyle( style: centerStyle, softWrap: false, overflow: TextOverflow.ellipsis, - child: title, + child: new Semantics( + namesRoute: namesRoute, + child: title, + header: true, + ), ); } @@ -626,7 +630,9 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { automaticallyImplyLeading: automaticallyImplyLeading, title: title, actions: actions, - flexibleSpace: flexibleSpace, + flexibleSpace: (title == null && flexibleSpace != null) + ? new Semantics(child: flexibleSpace, header: true) + : flexibleSpace, bottom: bottom, elevation: forceElevated || overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent) ? elevation ?? 4.0 : 0.0, backgroundColor: backgroundColor, diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index fd3e080bf4..b74f2ea8e3 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -8,6 +8,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart' hide TypeMatcher; +import '../widgets/semantics_tester.dart'; + int count = 0; void main() { @@ -567,6 +569,68 @@ void main() { expect(decoration.border, isNull); }); + testWidgets('CupertinoSliverNavigationBar has semantics', (WidgetTester tester) async { + final SemanticsTester semantics = new SemanticsTester(tester); + + await tester.pumpWidget(new WidgetsApp( + color: const Color(0xFFFFFFFF), + onGenerateRoute: (RouteSettings settings) { + return new CupertinoPageRoute( + settings: settings, + builder: (BuildContext context) { + return new CupertinoPageScaffold( + child: new CustomScrollView( + slivers: const [ + const CupertinoSliverNavigationBar( + largeTitle: const Text('Large Title'), + border: null, + ), + ], + ), + ); + }, + ); + } + )); + + expect(semantics.nodesWith( + label: 'Large Title', + flags: [SemanticsFlag.isHeader], + textDirection: TextDirection.ltr, + ), hasLength(1)); + + semantics.dispose(); + }); + + testWidgets('CupertinoNavigationBar has semantics', (WidgetTester tester) async { + final SemanticsTester semantics = new SemanticsTester(tester); + + await tester.pumpWidget(new WidgetsApp( + color: const Color(0xFFFFFFFF), + onGenerateRoute: (RouteSettings settings) { + return new CupertinoPageRoute( + settings: settings, + builder: (BuildContext context) { + return new CupertinoPageScaffold( + navigationBar: const CupertinoNavigationBar( + middle: const Text('Fixed Title'), + ), + child: new Container(), + ); + }, + ); + } + )); + + expect(semantics.nodesWith( + label: 'Fixed Title', + flags: [SemanticsFlag.isHeader], + textDirection: TextDirection.ltr, + ), hasLength(1)); + + semantics.dispose(); + }); + testWidgets( 'Border can be overridden in sliver nav bar', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 4f17a37968..602e418bfc 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -1214,7 +1214,10 @@ void main() { textDirection: TextDirection.ltr, ), new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Title', textDirection: TextDirection.ltr, ), @@ -1297,7 +1300,10 @@ void main() { textDirection: TextDirection.rtl, ), new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Title', textDirection: TextDirection.rtl, ), diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 0557a3d6e9..8f594fa9be 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -789,7 +789,10 @@ void main() { )); expect(semantics, includesNodeWith( label: 'Page 1', - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], )); await tester.tap(find.text('1')); // pushNamed('/A') @@ -801,7 +804,10 @@ void main() { )); expect(semantics, includesNodeWith( label: 'Page 2', - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], )); await tester.tap(find.text('2')); // pushNamed('/B/C') @@ -809,11 +815,16 @@ void main() { await tester.pump(const Duration(seconds: 1)); expect(semantics, includesNodeWith( - flags: [SemanticsFlag.scopesRoute], + flags: [ + SemanticsFlag.scopesRoute, + ], )); expect(semantics, includesNodeWith( label: 'Page 3', - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], )); diff --git a/packages/flutter/test/widgets/sliver_semantics_test.dart b/packages/flutter/test/widgets/sliver_semantics_test.dart index 9ff1110407..08e581405e 100644 --- a/packages/flutter/test/widgets/sliver_semantics_test.dart +++ b/packages/flutter/test/widgets/sliver_semantics_test.dart @@ -79,7 +79,10 @@ void _tests() { children: [ new TestSemantics( id: 8, - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Semantics Test with Slivers', textDirection: TextDirection.ltr, ), @@ -140,7 +143,10 @@ void _tests() { children: [ new TestSemantics( id: 8, - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Semantics Test with Slivers', textDirection: TextDirection.ltr, ), @@ -219,7 +225,10 @@ void _tests() { children: [ new TestSemantics( id: 8, - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Semantics Test with Slivers', textDirection: TextDirection.ltr, ), @@ -458,7 +467,10 @@ void _tests() { tags: [RenderViewport.excludeFromScrolling], children: [ new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'AppBar', textDirection: TextDirection.ltr, ), @@ -557,7 +569,10 @@ void _tests() { tags: [RenderViewport.excludeFromScrolling], children: [ new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'AppBar', textDirection: TextDirection.ltr, ), @@ -693,7 +708,10 @@ void _tests() { tags: [RenderViewport.excludeFromScrolling], children: [ new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'AppBar', textDirection: TextDirection.ltr, ), @@ -791,7 +809,10 @@ void _tests() { tags: [RenderViewport.excludeFromScrolling], children: [ new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'AppBar', textDirection: TextDirection.ltr, ), @@ -883,7 +904,10 @@ void _tests() { tags: [RenderViewport.excludeFromScrolling], children: [ new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Forward app bar', textDirection: TextDirection.ltr, ), @@ -986,7 +1010,10 @@ void _tests() { tags: [RenderViewport.excludeFromScrolling], children: [ new TestSemantics( - flags: [SemanticsFlag.namesRoute], + flags: [ + SemanticsFlag.namesRoute, + SemanticsFlag.isHeader, + ], label: 'Backward app bar', textDirection: TextDirection.ltr, ),