diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index 84ee0e1dee..7476f88992 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -47,6 +47,7 @@ class FlexibleSpaceBar extends StatefulWidget { this.title, this.background, this.centerTitle, + this.titlePadding, this.collapseMode = CollapseMode.parallax }) : assert(collapseMode != null), super(key: key); @@ -63,7 +64,8 @@ class FlexibleSpaceBar extends StatefulWidget { /// Whether the title should be centered. /// - /// Defaults to being adapted to the current [TargetPlatform]. + /// By default this property is true if the current target platform + /// is [TargetPlatform.iOS], false otherwise. final bool centerTitle; /// Collapse effect while scrolling. @@ -71,6 +73,18 @@ class FlexibleSpaceBar extends StatefulWidget { /// Defaults to [CollapseMode.parallax]. final CollapseMode collapseMode; + /// Defines how far the [title] is inset from either the widget's + /// bottom-left or its center. + /// + /// Typically this property is used to adjust how far the title is + /// is inset from the bottom-left and it is specified along with + /// [centerTitle] false. + /// + /// By default the value of this property is + /// `EdgeInsetsDirectional.only(start: 72, bottom: 16)` if the title is + /// not centered, `EdgeInsetsDirectional.only(start 0, bottom: 16)` otherwise. + final EdgeInsetsGeometry titlePadding; + /// Wraps a widget that contains an [AppBar] to convey sizing information down /// to the [FlexibleSpaceBar]. /// @@ -206,15 +220,17 @@ class _FlexibleSpaceBarState extends State { color: titleStyle.color.withOpacity(opacity) ); final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme); + final EdgeInsetsGeometry padding = widget.titlePadding ?? + EdgeInsetsDirectional.only( + start: effectiveCenterTitle ? 0.0 : 72.0, + bottom: 16.0 + ); final double scaleValue = Tween(begin: 1.5, end: 1.0).transform(t); final Matrix4 scaleTransform = Matrix4.identity() ..scale(scaleValue, scaleValue, 1.0); final Alignment titleAlignment = _getTitleAlignment(effectiveCenterTitle); children.add(Container( - padding: EdgeInsetsDirectional.only( - start: effectiveCenterTitle ? 0.0 : 72.0, - bottom: 16.0 - ), + padding: padding, child: Transform( alignment: titleAlignment, transform: scaleTransform, diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index e3c7c13fb1..52aef0fc97 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -114,6 +114,88 @@ void main() { expect(clipRect.size.height, minExtent); }); + + testWidgets('FlexibleSpaceBar test titlePadding defaults', (WidgetTester tester) async { + Widget buildFrame(TargetPlatform platform, bool centerTitle) { + return MaterialApp( + theme: ThemeData(platform: platform), + home: Scaffold( + appBar: AppBar( + flexibleSpace: FlexibleSpaceBar( + centerTitle: centerTitle, + title: const Text('X'), + ), + ), + ), + ); + } + + final Finder title = find.text('X'); + final Finder flexibleSpaceBar = find.byType(FlexibleSpaceBar); + Offset getTitleBottomLeft() { + return Offset( + tester.getTopLeft(title).dx, + tester.getBottomRight(flexibleSpaceBar).dy - tester.getBottomRight(title).dy, + ); + } + + await tester.pumpWidget(buildFrame(TargetPlatform.android, null)); + expect(getTitleBottomLeft(), const Offset(72.0, 16.0)); + + await tester.pumpWidget(buildFrame(TargetPlatform.android, true)); + expect(getTitleBottomLeft(), const Offset(390.0, 16.0)); + + // Clear the widget tree to avoid animating between Android and iOS. + await tester.pumpWidget(Container(key: UniqueKey())); + + await tester.pumpWidget(buildFrame(TargetPlatform.iOS, null)); + expect(getTitleBottomLeft(), const Offset(390.0, 16.0)); + + await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false)); + expect(getTitleBottomLeft(), const Offset(72.0, 16.0)); + + }); + + testWidgets('FlexibleSpaceBar test titlePadding override', (WidgetTester tester) async { + Widget buildFrame(TargetPlatform platform, bool centerTitle) { + return MaterialApp( + theme: ThemeData(platform: platform), + home: Scaffold( + appBar: AppBar( + flexibleSpace: FlexibleSpaceBar( + titlePadding: EdgeInsets.zero, + centerTitle: centerTitle, + title: const Text('X'), + ), + ), + ), + ); + } + + final Finder title = find.text('X'); + final Finder flexibleSpaceBar = find.byType(FlexibleSpaceBar); + Offset getTitleBottomLeft() { + return Offset( + tester.getTopLeft(title).dx, + tester.getBottomRight(flexibleSpaceBar).dy - tester.getBottomRight(title).dy, + ); + } + + await tester.pumpWidget(buildFrame(TargetPlatform.android, null)); + expect(getTitleBottomLeft(), Offset.zero); + + await tester.pumpWidget(buildFrame(TargetPlatform.android, true)); + expect(getTitleBottomLeft(), const Offset(390.0, 0.0)); + + // Clear the widget tree to avoid animating between Android and iOS. + await tester.pumpWidget(Container(key: UniqueKey())); + + await tester.pumpWidget(buildFrame(TargetPlatform.iOS, null)); + expect(getTitleBottomLeft(), const Offset(390.0, 0.0)); + + await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false)); + expect(getTitleBottomLeft(), Offset.zero); + }); } class TestDelegate extends SliverPersistentHeaderDelegate {