[Material] Allow Appbar to exclude header semantics (#52894)
This commit is contained in:
parent
bbc9d4f3a6
commit
e2610a450c
@ -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 {
|
|||||||
/// 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> {
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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
|
|||||||
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() {
|
|||||||
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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user