Unverified Commit 56e1bddc authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Fix `SliverAppBar.medium` & `SliverAppBar.large` title overlap with...

Fix `SliverAppBar.medium` & `SliverAppBar.large` title overlap with leading/actions widgets, leading width, and title spacing (#120780)

* Fix `SliverAppBar.medium` & `SliverAppBar.large` title overlap with leading/actions widgets, leading width, and title spacing

* Add `titleSpacing` theme tests and consolidate multiple tests for the same widgets
parent af347d66
...@@ -79,10 +79,10 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig { ...@@ -79,10 +79,10 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
${textStyle('md.comp.top-app-bar.medium.headline')}?.apply(color: ${color('md.comp.top-app-bar.medium.headline.color')}); ${textStyle('md.comp.top-app-bar.medium.headline')}?.apply(color: ${color('md.comp.top-app-bar.medium.headline.color')});
@override @override
EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.fromSTEB(48, 0, 16, 0); EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 0); EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20); EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20);
...@@ -108,10 +108,10 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig { ...@@ -108,10 +108,10 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
${textStyle('md.comp.top-app-bar.large.headline')}?.apply(color: ${color('md.comp.top-app-bar.large.headline.color')}); ${textStyle('md.comp.top-app-bar.large.headline')}?.apply(color: ${color('md.comp.top-app-bar.large.headline.color')});
@override @override
EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.fromSTEB(48, 0, 16, 0); EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 0); EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28); EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28);
......
...@@ -1528,13 +1528,16 @@ class SliverAppBar extends StatefulWidget { ...@@ -1528,13 +1528,16 @@ class SliverAppBar extends StatefulWidget {
key: key, key: key,
leading: leading, leading: leading,
automaticallyImplyLeading: automaticallyImplyLeading, automaticallyImplyLeading: automaticallyImplyLeading,
actions: actions,
flexibleSpace: flexibleSpace ?? _ScrollUnderFlexibleSpace( flexibleSpace: flexibleSpace ?? _ScrollUnderFlexibleSpace(
hasLeading: leading != null,
title: title, title: title,
actions: actions,
foregroundColor: foregroundColor, foregroundColor: foregroundColor,
variant: _ScrollUnderFlexibleVariant.medium, variant: _ScrollUnderFlexibleVariant.medium,
centerCollapsedTitle: centerTitle, centerCollapsedTitle: centerTitle,
primary: primary, primary: primary,
leadingWidth: leadingWidth,
titleSpacing: titleSpacing,
), ),
bottom: bottom, bottom: bottom,
elevation: elevation, elevation: elevation,
...@@ -1630,13 +1633,16 @@ class SliverAppBar extends StatefulWidget { ...@@ -1630,13 +1633,16 @@ class SliverAppBar extends StatefulWidget {
key: key, key: key,
leading: leading, leading: leading,
automaticallyImplyLeading: automaticallyImplyLeading, automaticallyImplyLeading: automaticallyImplyLeading,
actions: actions,
flexibleSpace: flexibleSpace ?? _ScrollUnderFlexibleSpace( flexibleSpace: flexibleSpace ?? _ScrollUnderFlexibleSpace(
hasLeading: leading != null,
title: title, title: title,
actions: actions,
foregroundColor: foregroundColor, foregroundColor: foregroundColor,
variant: _ScrollUnderFlexibleVariant.large, variant: _ScrollUnderFlexibleVariant.large,
centerCollapsedTitle: centerTitle, centerCollapsedTitle: centerTitle,
primary: primary, primary: primary,
leadingWidth: leadingWidth,
titleSpacing: titleSpacing,
), ),
bottom: bottom, bottom: bottom,
elevation: elevation, elevation: elevation,
...@@ -2077,18 +2083,26 @@ enum _ScrollUnderFlexibleVariant { medium, large } ...@@ -2077,18 +2083,26 @@ enum _ScrollUnderFlexibleVariant { medium, large }
class _ScrollUnderFlexibleSpace extends StatelessWidget { class _ScrollUnderFlexibleSpace extends StatelessWidget {
const _ScrollUnderFlexibleSpace({ const _ScrollUnderFlexibleSpace({
required this.hasLeading,
this.title, this.title,
this.actions,
this.foregroundColor, this.foregroundColor,
required this.variant, required this.variant,
this.centerCollapsedTitle, this.centerCollapsedTitle,
this.primary = true, this.primary = true,
this.leadingWidth,
this.titleSpacing,
}); });
final bool hasLeading;
final Widget? title; final Widget? title;
final List<Widget>? actions;
final Color? foregroundColor; final Color? foregroundColor;
final _ScrollUnderFlexibleVariant variant; final _ScrollUnderFlexibleVariant variant;
final bool? centerCollapsedTitle; final bool? centerCollapsedTitle;
final bool primary; final bool primary;
final double? leadingWidth;
final double? titleSpacing;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -2142,6 +2156,14 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget { ...@@ -2142,6 +2156,14 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget {
centerTitle = centerCollapsedTitle ?? appBarTheme.centerTitle ?? platformCenter(); centerTitle = centerCollapsedTitle ?? appBarTheme.centerTitle ?? platformCenter();
} }
EdgeInsetsGeometry effectiveCollapsedTitlePadding = EdgeInsets.zero;
if (hasLeading && leadingWidth == null) {
effectiveCollapsedTitlePadding = centerTitle
? config.collapsedCenteredTitlePadding!
: config.collapsedTitlePadding!;
} else if (hasLeading && leadingWidth != null) {
effectiveCollapsedTitlePadding = EdgeInsetsDirectional.only(start: leadingWidth!);
}
final bool isCollapsed = settings.isScrolledUnder ?? false; final bool isCollapsed = settings.isScrolledUnder ?? false;
return Column( return Column(
children: <Widget>[ children: <Widget>[
...@@ -2149,17 +2171,20 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget { ...@@ -2149,17 +2171,20 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget {
padding: EdgeInsets.only(top: topPadding), padding: EdgeInsets.only(top: topPadding),
child: Container( child: Container(
height: collapsedHeight, height: collapsedHeight,
padding: centerTitle ? config.collapsedCenteredTitlePadding : config.collapsedTitlePadding, padding: effectiveCollapsedTitlePadding,
child: AnimatedOpacity( child: NavigationToolbar(
opacity: isCollapsed ? 1 : 0, centerMiddle: centerTitle,
duration: const Duration(milliseconds: 500), middleSpacing: titleSpacing ?? appBarTheme.titleSpacing ?? NavigationToolbar.kMiddleSpacing,
curve: const Cubic(0.2, 0.0, 0.0, 1.0), middle: AnimatedOpacity(
child: Align( opacity: isCollapsed ? 1 : 0,
alignment: centerTitle duration: const Duration(milliseconds: 500),
? Alignment.center curve: const Cubic(0.2, 0.0, 0.0, 1.0),
: AlignmentDirectional.centerStart,
child: collapsedTitle, child: collapsedTitle,
), ),
trailing: actions != null ? Row(
mainAxisSize: MainAxisSize.min,
children: actions!,
) : null,
), ),
), ),
), ),
...@@ -2295,10 +2320,10 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig { ...@@ -2295,10 +2320,10 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
_textTheme.headlineSmall?.apply(color: _colors.onSurface); _textTheme.headlineSmall?.apply(color: _colors.onSurface);
@override @override
EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.fromSTEB(48, 0, 16, 0); EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 0); EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20); EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20);
...@@ -2324,10 +2349,10 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig { ...@@ -2324,10 +2349,10 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
_textTheme.headlineMedium?.apply(color: _colors.onSurface); _textTheme.headlineMedium?.apply(color: _colors.onSurface);
@override @override
EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.fromSTEB(48, 0, 16, 0); EdgeInsetsGeometry? get collapsedTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 0); EdgeInsetsGeometry? get collapsedCenteredTitlePadding => const EdgeInsetsDirectional.only(start: 40);
@override @override
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28); EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28);
......
...@@ -3974,6 +3974,401 @@ void main() { ...@@ -3974,6 +3974,401 @@ void main() {
expect(tester.getSize(find.byKey(leadingKey)).width, leadingWidth); expect(tester.getSize(find.byKey(leadingKey)).width, leadingWidth);
}); });
testWidgets(
'SliverAppBar.medium collapsed title does not overlap with leading/actions widgets',
(WidgetTester tester) async {
const String title = 'Medium SliverAppBar Very Long Title';
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 200),
sliver: SliverAppBar.medium(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
title: const Text(title, maxLines: 1),
actions: const <Widget>[
Icon(Icons.search),
Icon(Icons.sort),
Icon(Icons.more_vert),
],
),
),
SliverToBoxAdapter(
child: Container(
height: 1200,
color: Colors.orange[400],
),
),
],
),
),
));
// Scroll to collapse the SliverAppBar.
final ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
final Offset leadingOffset = tester.getTopRight(find.byIcon(Icons.menu));
Offset titleOffset = tester.getTopLeft(find.text(title).first);
// The title widget should be to the right of the leading widget.
expect(titleOffset.dx, greaterThan(leadingOffset.dx));
titleOffset = tester.getTopRight(find.text(title).first);
final Offset searchOffset = tester.getTopLeft(find.byIcon(Icons.search));
// The title widget should be to the left of the search icon.
expect(titleOffset.dx, lessThan(searchOffset.dx));
});
testWidgets(
'SliverAppBar.large collapsed title does not overlap with leading/actions widgets',
(WidgetTester tester) async {
const String title = 'Large SliverAppBar Very Long Title';
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 200),
sliver: SliverAppBar.large(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
title: const Text(title, maxLines: 1),
actions: const <Widget>[
Icon(Icons.search),
Icon(Icons.sort),
Icon(Icons.more_vert),
],
),
),
SliverToBoxAdapter(
child: Container(
height: 1200,
color: Colors.orange[400],
),
),
],
),
),
));
// Scroll to collapse the SliverAppBar.
final ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
final Offset leadingOffset = tester.getTopRight(find.byIcon(Icons.menu));
Offset titleOffset = tester.getTopLeft(find.text(title).first);
// The title widget should be to the right of the leading widget.
expect(titleOffset.dx, greaterThan(leadingOffset.dx));
titleOffset = tester.getTopRight(find.text(title).first);
final Offset searchOffset = tester.getTopLeft(find.byIcon(Icons.search));
// The title widget should be to the left of the search icon.
expect(titleOffset.dx, lessThan(searchOffset.dx));
});
testWidgets('SliverAppBar.medium respects title spacing', (WidgetTester tester) async {
const String title = 'Medium SliverAppBar Very Long Title';
const double titleSpacing = 16.0;
Widget buildWidget({double? titleSpacing, bool? centerTitle}) {
return MaterialApp(
home: Scaffold(
body: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverAppBar.medium(
centerTitle: centerTitle,
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
title: const Text(title, maxLines: 1),
titleSpacing: titleSpacing,
actions: const <Widget>[
Icon(Icons.sort),
Icon(Icons.more_vert),
],
),
SliverToBoxAdapter(
child: Container(
height: 1200,
color: Colors.orange[400],
),
),
],
),
),
);
}
await tester.pumpWidget(buildWidget());
// Scroll to collapse the SliverAppBar.
ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// By default, title widget should be to the right of the
// leading widget and title spacing should be respected.
Offset titleOffset = tester.getTopLeft(find.text(title).first);
Offset iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
expect(titleOffset.dx, iconOffset.dx + titleSpacing);
await tester.pumpWidget(buildWidget(centerTitle: true));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// By default, title widget should be to the left of the first
// leading widget and title spacing should be respected.
titleOffset = tester.getTopRight(find.text(title).first);
iconOffset = tester.getTopLeft(find.byIcon(Icons.sort));
expect(titleOffset.dx, iconOffset.dx - titleSpacing);
// Test custom title spacing, set to 0.0.
await tester.pumpWidget(buildWidget(titleSpacing: 0.0));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// The title widget should be to the right of the leading
// widget with no spacing.
titleOffset = tester.getTopLeft(find.text(title).first);
iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
expect(titleOffset.dx, iconOffset.dx);
// Set centerTitle to true so the end of the title can reach
// the action widgets.
await tester.pumpWidget(buildWidget(titleSpacing: 0.0, centerTitle: true));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// The title widget should be to the left of the first
// leading widget with no spacing.
titleOffset = tester.getTopRight(find.text(title).first);
iconOffset = tester.getTopLeft(find.byIcon(Icons.sort));
expect(titleOffset.dx, iconOffset.dx);
});
testWidgets('SliverAppBar.large respects title spacing', (WidgetTester tester) async {
const String title = 'Large SliverAppBar Very Long Title';
const double titleSpacing = 16.0;
Widget buildWidget({double? titleSpacing, bool? centerTitle}) {
return MaterialApp(
home: Scaffold(
body: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverAppBar.large(
centerTitle: centerTitle,
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
title: const Text(title, maxLines: 1),
titleSpacing: titleSpacing,
actions: const <Widget>[
Icon(Icons.sort),
Icon(Icons.more_vert),
],
),
SliverToBoxAdapter(
child: Container(
height: 1200,
color: Colors.orange[400],
),
),
],
),
),
);
}
await tester.pumpWidget(buildWidget());
// Scroll to collapse the SliverAppBar.
ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// By default, title widget should be to the right of the leading
// widget and title spacing should be respected.
Offset titleOffset = tester.getTopLeft(find.text(title).first);
Offset iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
expect(titleOffset.dx, iconOffset.dx + titleSpacing);
await tester.pumpWidget(buildWidget(centerTitle: true));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// By default, title widget should be to the right of the
// leading widget and title spacing should be respected.
titleOffset = tester.getTopRight(find.text(title).first);
iconOffset = tester.getTopLeft(find.byIcon(Icons.sort));
expect(titleOffset.dx, iconOffset.dx - titleSpacing);
// Test custom title spacing, set to 0.0.
await tester.pumpWidget(buildWidget(titleSpacing: 0.0));
controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// The title widget should be to the right of the leading
// widget with no spacing.
titleOffset = tester.getTopLeft(find.text(title).first);
iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
expect(titleOffset.dx, iconOffset.dx);
// Set centerTitle to true so the end of the title can reach
// the action widgets.
await tester.pumpWidget(buildWidget(titleSpacing: 0.0, centerTitle: true));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
// The title widget should be to the left of the first
// leading widget with no spacing.
titleOffset = tester.getTopRight(find.text(title).first);
iconOffset = tester.getTopLeft(find.byIcon(Icons.sort));
expect(titleOffset.dx, iconOffset.dx);
});
testWidgets(
'SliverAppBar.medium without the leading widget updates collapsed title padding',
(WidgetTester widgetTester) async {
const String title = 'Medium SliverAppBar Title';
const double leadingPadding = 40.0;
const double titleSpacing = 16.0;
Widget buildWidget({ bool showLeading = true }) {
return MaterialApp(
home: Scaffold(
body: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverAppBar.medium(
leading: showLeading
? IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
)
: null,
title: const Text(title),
),
SliverToBoxAdapter(
child: Container(
height: 1200,
color: Colors.orange[400],
),
),
],
),
),
);
}
await widgetTester.pumpWidget(buildWidget());
// Scroll to collapse the SliverAppBar.
ScrollController controller = primaryScrollController(widgetTester);
controller.jumpTo(45);
await widgetTester.pumpAndSettle();
// If the leading widget is present, the title widget should be to the
// right of the leading widget and title spacing should be respected.
Offset titleOffset = widgetTester.getTopLeft(find.text(title).first);
expect(titleOffset.dx, leadingPadding + titleSpacing);
// Hide the leading widget.
await widgetTester.pumpWidget(buildWidget(showLeading: false));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(widgetTester);
controller.jumpTo(45);
await widgetTester.pumpAndSettle();
// If the leading widget is not present, the title widget will
// only have the default title spacing.
titleOffset = widgetTester.getTopLeft(find.text(title).first);
expect(titleOffset.dx, titleSpacing);
});
testWidgets(
'SliverAppBar.large without the leading widget updates collapsed title padding',
(WidgetTester widgetTester) async {
const String title = 'Large SliverAppBar Title';
const double leadingPadding = 40.0;
const double titleSpacing = 16.0;
Widget buildWidget({ bool showLeading = true }) {
return MaterialApp(
home: Scaffold(
body: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverAppBar.large(
leading: showLeading
? IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
)
: null,
title: const Text(title),
),
SliverToBoxAdapter(
child: Container(
height: 1200,
color: Colors.orange[400],
),
),
],
),
),
);
}
await widgetTester.pumpWidget(buildWidget());
// Scroll CustomScrollView to collapse SliverAppBar.
ScrollController controller = primaryScrollController(widgetTester);
controller.jumpTo(45);
await widgetTester.pumpAndSettle();
// If the leading widget is present, the title widget should be to the
// right of the leading widget and title spacing should be respected.
Offset titleOffset = widgetTester.getTopLeft(find.text(title).first);
expect(titleOffset.dx, leadingPadding + titleSpacing);
// Hide the leading widget.
await widgetTester.pumpWidget(buildWidget(showLeading: false));
// Scroll to collapse the SliverAppBar.
controller = primaryScrollController(widgetTester);
controller.jumpTo(45);
await widgetTester.pumpAndSettle();
// If the leading widget is not present, the title widget will
// only have the default title spacing.
titleOffset = widgetTester.getTopLeft(find.text(title).first);
expect(titleOffset.dx, titleSpacing);
});
group('AppBar.forceMaterialTransparency', () { group('AppBar.forceMaterialTransparency', () {
Material getAppBarMaterial(WidgetTester tester) { Material getAppBarMaterial(WidgetTester tester) {
return tester.widget<Material>(find return tester.widget<Material>(find
...@@ -4026,25 +4421,26 @@ void main() { ...@@ -4026,25 +4421,26 @@ void main() {
}); });
testWidgets( testWidgets(
'forceMaterialTransparency == false does not allow gestures beneath the app bar', (WidgetTester tester) async { 'forceMaterialTransparency == false does not allow gestures beneath the app bar',
// Set this, and tester.tap(warnIfMissed:false), to suppress (WidgetTester tester) async {
// errors/warning that the button is not hittable (which is expected). // Set this, and tester.tap(warnIfMissed:false), to suppress
WidgetController.hitTestWarningShouldBeFatal = false; // errors/warning that the button is not hittable (which is expected).
WidgetController.hitTestWarningShouldBeFatal = false;
bool buttonWasPressed = false;
final Widget widget = buildWidget( bool buttonWasPressed = false;
forceMaterialTransparency:false, final Widget widget = buildWidget(
onPressed:() { buttonWasPressed = true; }, forceMaterialTransparency:false,
); onPressed:() { buttonWasPressed = true; },
await tester.pumpWidget(widget); );
await tester.pumpWidget(widget);
final Material material = getAppBarMaterial(tester); final Material material = getAppBarMaterial(tester);
expect(material.type, MaterialType.canvas); expect(material.type, MaterialType.canvas);
final Finder buttonFinder = find.byType(TextButton); final Finder buttonFinder = find.byType(TextButton);
await tester.tap(buttonFinder, warnIfMissed:false); await tester.tap(buttonFinder, warnIfMissed:false);
await tester.pump(); await tester.pump();
expect(buttonWasPressed, isFalse); expect(buttonWasPressed, isFalse);
}); });
}); });
} }
...@@ -9,6 +9,10 @@ import 'package:flutter/services.dart'; ...@@ -9,6 +9,10 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
ScrollController primaryScrollController(WidgetTester tester) {
return PrimaryScrollController.of(tester.element(find.byType(CustomScrollView)));
}
test('AppBarTheme copyWith, ==, hashCode basics', () { test('AppBarTheme copyWith, ==, hashCode basics', () {
expect(const AppBarTheme(), const AppBarTheme().copyWith()); expect(const AppBarTheme(), const AppBarTheme().copyWith());
expect(const AppBarTheme().hashCode, const AppBarTheme().copyWith().hashCode); expect(const AppBarTheme().hashCode, const AppBarTheme().copyWith().hashCode);
...@@ -676,14 +680,28 @@ void main() { ...@@ -676,14 +680,28 @@ void main() {
expect(navToolbar.middleSpacing, 40); expect(navToolbar.middleSpacing, 40);
}); });
testWidgets("SliverAppBar.medium's title uses AppBarTheme.foregroundColor", (WidgetTester tester) async { testWidgets('SliverAppBar.medium uses AppBarTheme properties', (WidgetTester tester) async {
const String title = 'Medium SliverAppBar Title';
const Color foregroundColor = Color(0xff00ff00); const Color foregroundColor = Color(0xff00ff00);
const double titleSpacing = 10.0;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(appBarTheme: const AppBarTheme(foregroundColor: foregroundColor)), theme: ThemeData(
appBarTheme: const AppBarTheme(
foregroundColor: foregroundColor,
titleSpacing: titleSpacing,
centerTitle: false,
),
),
home: CustomScrollView( home: CustomScrollView(
primary: true,
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar.medium( SliverAppBar.medium(
title: const Text('Medium Title'), leading: IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
title: const Text(title),
), ),
], ],
), ),
...@@ -691,35 +709,84 @@ void main() { ...@@ -691,35 +709,84 @@ void main() {
final RichText text = tester.firstWidget(find.byType(RichText)); final RichText text = tester.firstWidget(find.byType(RichText));
expect(text.text.style!.color, foregroundColor); expect(text.text.style!.color, foregroundColor);
// Scroll to collapse the SliverAppBar.
final ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
final Offset titleOffset = tester.getTopLeft(find.text(title).first);
final Offset iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
// Title spacing should be 10.0.
expect(titleOffset.dx, iconOffset.dx + titleSpacing);
}); });
testWidgets( testWidgets('SliverAppBar.medium properties take priority over AppBarTheme properties', (WidgetTester tester) async {
"SliverAppBar.medium's foregroundColor takes priority over AppBarTheme.foregroundColor", (WidgetTester tester) async { const String title = 'Medium SliverAppBar Title';
const Color foregroundColor = Color(0xff00ff00); const Color foregroundColor = Color(0xff00ff00);
await tester.pumpWidget(MaterialApp( const double titleSpacing = 10.0;
theme: ThemeData(appBarTheme: const AppBarTheme(foregroundColor: Color(0xffff0000))),
home: CustomScrollView( await tester.pumpWidget(MaterialApp(
slivers: <Widget>[ theme: ThemeData(
SliverAppBar.medium( appBarTheme: const AppBarTheme(
foregroundColor: foregroundColor, foregroundColor: Color(0xffff0000),
title: const Text('Medium Title'), titleSpacing: 14.0,
), centerTitle: true,
],
), ),
)); ),
home: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverAppBar.medium(
centerTitle: false,
titleSpacing: titleSpacing,
foregroundColor: foregroundColor,
leading: IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
title: const Text(title),
),
],
),
));
final RichText text = tester.firstWidget(find.byType(RichText));
expect(text.text.style!.color, foregroundColor);
// Scroll to collapse the SliverAppBar.
final ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
final RichText text = tester.firstWidget(find.byType(RichText)); final Offset titleOffset = tester.getTopLeft(find.text(title).first);
expect(text.text.style!.color, foregroundColor); final Offset iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
// Title spacing should be 10.0.
expect(titleOffset.dx, iconOffset.dx + titleSpacing);
}); });
testWidgets("SliverAppBar.large's title uses AppBarTheme.foregroundColor", (WidgetTester tester) async { testWidgets('SliverAppBar.large uses AppBarTheme properties', (WidgetTester tester) async {
const String title = 'Large SliverAppBar Title';
const Color foregroundColor = Color(0xff00ff00); const Color foregroundColor = Color(0xff00ff00);
const double titleSpacing = 10.0;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(appBarTheme: const AppBarTheme(foregroundColor: foregroundColor)), theme: ThemeData(
appBarTheme: const AppBarTheme(
foregroundColor: foregroundColor,
titleSpacing: titleSpacing,
centerTitle: false,
),
),
home: CustomScrollView( home: CustomScrollView(
primary: true,
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar.large( SliverAppBar.large(
title: const Text('Large Title'), leading: IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
title: const Text(title),
), ),
], ],
), ),
...@@ -727,25 +794,60 @@ void main() { ...@@ -727,25 +794,60 @@ void main() {
final RichText text = tester.firstWidget(find.byType(RichText)); final RichText text = tester.firstWidget(find.byType(RichText));
expect(text.text.style!.color, foregroundColor); expect(text.text.style!.color, foregroundColor);
// Scroll to collapse the SliverAppBar.
final ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
final Offset titleOffset = tester.getTopLeft(find.text(title).first);
final Offset iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
// Title spacing should be 10.0.
expect(titleOffset.dx, iconOffset.dx + titleSpacing);
}); });
testWidgets( testWidgets('SliverAppBar.large properties take priority over AppBarTheme properties', (WidgetTester tester) async {
"SliverAppBar.large's foregroundColor takes priority over AppBarTheme.foregroundColor", (WidgetTester tester) async { const String title = 'Large SliverAppBar Title';
const Color foregroundColor = Color(0xff00ff00); const Color foregroundColor = Color(0xff00ff00);
await tester.pumpWidget(MaterialApp( const double titleSpacing = 10.0;
theme: ThemeData(appBarTheme: const AppBarTheme(foregroundColor: Color(0xffff0000))),
home: CustomScrollView( await tester.pumpWidget(MaterialApp(
slivers: <Widget>[ theme: ThemeData(
SliverAppBar.large( appBarTheme: const AppBarTheme(
foregroundColor: foregroundColor, foregroundColor: Color(0xffff0000),
title: const Text('Large Title'), titleSpacing: 14.0,
), centerTitle: true,
],
), ),
)); ),
home: CustomScrollView(
primary: true,
slivers: <Widget>[
SliverAppBar.large(
centerTitle: false,
titleSpacing: titleSpacing,
foregroundColor: foregroundColor,
leading: IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
title: const Text(title),
),
],
),
));
final RichText text = tester.firstWidget(find.byType(RichText));
expect(text.text.style!.color, foregroundColor);
// Scroll to collapse the SliverAppBar.
final ScrollController controller = primaryScrollController(tester);
controller.jumpTo(45);
await tester.pumpAndSettle();
final RichText text = tester.firstWidget(find.byType(RichText)); final Offset titleOffset = tester.getTopLeft(find.text(title).first);
expect(text.text.style!.color, foregroundColor); final Offset iconOffset = tester.getTopRight(find.byIcon(Icons.menu));
// Title spacing should be 10.0.
expect(titleOffset.dx, iconOffset.dx + titleSpacing);
}); });
testWidgets('Default AppBarTheme debugFillProperties', (WidgetTester tester) async { testWidgets('Default AppBarTheme debugFillProperties', (WidgetTester tester) async {
......
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