Unverified Commit e2610a45 authored by rami-a's avatar rami-a Committed by GitHub

[Material] Allow Appbar to exclude header semantics (#52894)

parent bbc9d4f3
...@@ -193,6 +193,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -193,6 +193,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
this.textTheme, this.textTheme,
this.primary = true, this.primary = true,
this.centerTitle, this.centerTitle,
this.excludeHeaderSemantics = false,
this.titleSpacing = NavigationToolbar.kMiddleSpacing, this.titleSpacing = NavigationToolbar.kMiddleSpacing,
this.toolbarOpacity = 1.0, this.toolbarOpacity = 1.0,
this.bottomOpacity = 1.0, this.bottomOpacity = 1.0,
...@@ -387,6 +388,11 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -387,6 +388,11 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// Defaults to being adapted to the current [TargetPlatform]. /// Defaults to being adapted to the current [TargetPlatform].
final bool centerTitle; final bool centerTitle;
/// Whether the title should be wrapped with header [Semantics].
///
/// Defaults to false.
final bool excludeHeaderSemantics;
/// The spacing around [title] content on the horizontal axis. This spacing is /// The spacing around [title] content on the horizontal axis. This spacing is
/// applied even if there is no [leading] content or [actions]. If you want /// applied even if there is no [leading] content or [actions]. If you want
/// [title] to take all the space available, set this value to 0.0. /// [title] to take all the space available, set this value to 0.0.
...@@ -526,15 +532,21 @@ class _AppBarState extends State<AppBar> { ...@@ -526,15 +532,21 @@ class _AppBarState extends State<AppBar> {
case TargetPlatform.macOS: case TargetPlatform.macOS:
break; break;
} }
title = _AppBarTitleBox(child: title);
if (!widget.excludeHeaderSemantics) {
title = Semantics(
namesRoute: namesRoute,
child: title,
header: true,
);
}
title = DefaultTextStyle( title = DefaultTextStyle(
style: centerStyle, style: centerStyle,
softWrap: false, softWrap: false,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
child: Semantics( child: title,
namesRoute: namesRoute,
child: _AppBarTitleBox(child: title),
header: true,
),
); );
} }
...@@ -725,6 +737,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -725,6 +737,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
@required this.textTheme, @required this.textTheme,
@required this.primary, @required this.primary,
@required this.centerTitle, @required this.centerTitle,
@required this.excludeHeaderSemantics,
@required this.titleSpacing, @required this.titleSpacing,
@required this.expandedHeight, @required this.expandedHeight,
@required this.collapsedHeight, @required this.collapsedHeight,
...@@ -752,6 +765,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -752,6 +765,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final TextTheme textTheme; final TextTheme textTheme;
final bool primary; final bool primary;
final bool centerTitle; final bool centerTitle;
final bool excludeHeaderSemantics;
final double titleSpacing; final double titleSpacing;
final double expandedHeight; final double expandedHeight;
final double collapsedHeight; final double collapsedHeight;
...@@ -803,7 +817,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -803,7 +817,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
automaticallyImplyLeading: automaticallyImplyLeading, automaticallyImplyLeading: automaticallyImplyLeading,
title: title, title: title,
actions: actions, actions: actions,
flexibleSpace: (title == null && flexibleSpace != null) flexibleSpace: (title == null && flexibleSpace != null && !excludeHeaderSemantics)
? Semantics(child: flexibleSpace, header: true) ? Semantics(child: flexibleSpace, header: true)
: flexibleSpace, : flexibleSpace,
bottom: bottom, bottom: bottom,
...@@ -815,6 +829,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -815,6 +829,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
textTheme: textTheme, textTheme: textTheme,
primary: primary, primary: primary,
centerTitle: centerTitle, centerTitle: centerTitle,
excludeHeaderSemantics: excludeHeaderSemantics,
titleSpacing: titleSpacing, titleSpacing: titleSpacing,
shape: shape, shape: shape,
toolbarOpacity: toolbarOpacity, toolbarOpacity: toolbarOpacity,
...@@ -956,6 +971,7 @@ class SliverAppBar extends StatefulWidget { ...@@ -956,6 +971,7 @@ class SliverAppBar extends StatefulWidget {
this.textTheme, this.textTheme,
this.primary = true, this.primary = true,
this.centerTitle, this.centerTitle,
this.excludeHeaderSemantics = false,
this.titleSpacing = NavigationToolbar.kMiddleSpacing, this.titleSpacing = NavigationToolbar.kMiddleSpacing,
this.expandedHeight, this.expandedHeight,
this.floating = false, this.floating = false,
...@@ -1120,6 +1136,11 @@ class SliverAppBar extends StatefulWidget { ...@@ -1120,6 +1136,11 @@ class SliverAppBar extends StatefulWidget {
/// Defaults to being adapted to the current [TargetPlatform]. /// Defaults to being adapted to the current [TargetPlatform].
final bool centerTitle; final bool centerTitle;
/// Whether the title should be wrapped with header [Semantics].
///
/// Defaults to false.
final bool excludeHeaderSemantics;
/// The spacing around [title] content on the horizontal axis. This spacing is /// The spacing around [title] content on the horizontal axis. This spacing is
/// applied even if there is no [leading] content or [actions]. If you want /// applied even if there is no [leading] content or [actions]. If you want
/// [title] to take all the space available, set this value to 0.0. /// [title] to take all the space available, set this value to 0.0.
...@@ -1309,6 +1330,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix ...@@ -1309,6 +1330,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
textTheme: widget.textTheme, textTheme: widget.textTheme,
primary: widget.primary, primary: widget.primary,
centerTitle: widget.centerTitle, centerTitle: widget.centerTitle,
excludeHeaderSemantics: widget.excludeHeaderSemantics,
titleSpacing: widget.titleSpacing, titleSpacing: widget.titleSpacing,
expandedHeight: widget.expandedHeight, expandedHeight: widget.expandedHeight,
collapsedHeight: collapsedHeight, collapsedHeight: collapsedHeight,
......
...@@ -1432,6 +1432,120 @@ void main() { ...@@ -1432,6 +1432,120 @@ void main() {
semantics.dispose(); semantics.dispose();
}); });
testWidgets('AppBar excludes header semantics correctly', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(
MaterialApp(
home: Center(
child: AppBar(
leading: const Text('Leading'),
title: const ExcludeSemantics(child: Text('Title')),
excludeHeaderSemantics: true,
actions: const <Widget>[
Text('Action 1'),
],
),
),
),
);
expect(semantics, hasSemantics(
TestSemantics.root(
children: <TestSemantics>[
TestSemantics(
children: <TestSemantics>[
TestSemantics(
flags: <SemanticsFlag>[SemanticsFlag.scopesRoute],
children: <TestSemantics>[
TestSemantics(
children: <TestSemantics>[
TestSemantics(
label: 'Leading',
textDirection: TextDirection.ltr,
),
TestSemantics(
label: 'Action 1',
textDirection: TextDirection.ltr,
),
],
),
],
),
],
),
],
),
ignoreRect: true,
ignoreTransform: true,
ignoreId: true,
));
semantics.dispose();
});
testWidgets('SliverAppBar excludes header semantics correctly', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(
const MaterialApp(
home: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
leading: Text('Leading'),
flexibleSpace: ExcludeSemantics(child: Text('Title')),
actions: <Widget>[Text('Action 1')],
excludeHeaderSemantics: true,
),
],
),
),
);
expect(semantics, hasSemantics(
TestSemantics.root(
children: <TestSemantics>[
TestSemantics(
textDirection: TextDirection.ltr,
children: <TestSemantics>[
TestSemantics(
flags: <SemanticsFlag>[SemanticsFlag.scopesRoute],
children: <TestSemantics>[
TestSemantics(
children: <TestSemantics>[
TestSemantics(
flags: <SemanticsFlag>[SemanticsFlag.hasImplicitScrolling],
children: <TestSemantics>[
TestSemantics(
children: <TestSemantics>[
TestSemantics(
label: 'Leading',
textDirection: TextDirection.ltr,
),
TestSemantics(
label: 'Action 1',
textDirection: TextDirection.ltr,
),
],
),
],
),
],
),
],
),
],
),
],
),
ignoreRect: true,
ignoreTransform: true,
ignoreId: true,
));
semantics.dispose();
});
testWidgets('AppBar draws a light system bar for a dark background', (WidgetTester tester) async { testWidgets('AppBar draws a light system bar for a dark background', (WidgetTester tester) async {
final ThemeData darkTheme = ThemeData.dark(); final ThemeData darkTheme = ThemeData.dark();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment