diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index 1ca2fe6121..ff8c739f86 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -82,7 +82,9 @@ class FlexibleSpaceBar extends StatefulWidget { this.titlePadding, this.collapseMode = CollapseMode.parallax, this.stretchModes = const [StretchMode.zoomBackground], + this.expandedTitleScale = 1.5, }) : assert(collapseMode != null), + assert(expandedTitleScale >= 1), super(key: key); /// The primary contents of the flexible space bar when expanded. @@ -123,6 +125,14 @@ class FlexibleSpaceBar extends StatefulWidget { /// not centered, `EdgeInsetsDirectional.only(start: 0, bottom: 16)` otherwise. final EdgeInsetsGeometry? titlePadding; + /// Defines how much the title is scaled when the FlexibleSpaceBar is expanded + /// due to the user scrolling downwards. The title is scaled uniformly on the + /// x and y axes while maintaining its bottom-left position (bottom-center if + /// [centerTitle] is true). + /// + /// Defaults to 1.5 and must be greater than 1. + final double expandedTitleScale; + /// Wraps a widget that contains an [AppBar] to convey sizing information down /// to the [FlexibleSpaceBar]. /// @@ -317,7 +327,7 @@ class _FlexibleSpaceBarState extends State { start: effectiveCenterTitle ? 0.0 : 72.0, bottom: 16.0, ); - final double scaleValue = Tween(begin: 1.5, end: 1.0).transform(t); + final double scaleValue = Tween(begin: widget.expandedTitleScale, end: 1.0).transform(t); final Matrix4 scaleTransform = Matrix4.identity() ..scale(scaleValue, scaleValue, 1.0); final Alignment titleAlignment = _getTitleAlignment(effectiveCenterTitle); diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index a39927bc2a..86f1034aac 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -470,6 +470,78 @@ void main() { ); }); + testWidgets('FlexibleSpaceBar sets constraints for the title - override expandedTitleScale', (WidgetTester tester) async { + const double titleFontSize = 20.0; + const double height = 300.0; + const double expandedTitleScale = 3.0; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: CustomScrollView( + slivers: [ + SliverAppBar( + expandedHeight: height, + pinned: true, + stretch: true, + flexibleSpace: FlexibleSpaceBar( + expandedTitleScale: expandedTitleScale, + titlePadding: EdgeInsets.zero, + title: Text( + 'X' * 41, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: titleFontSize,), + ), + centerTitle: false, + ), + ), + SliverList( + delegate: SliverChildListDelegate( + [ + for (int i = 0; i < 3; i++) + SizedBox( + height: 200.0, + child: Center(child: Text('Item $i')), + ), + ], + ), + ), + ], + ), + ), + ), + ); + + // We drag up to fully collapse the space bar. + await tester.drag(find.text('Item 0'), const Offset(0, -600.0)); + await tester.pumpAndSettle(); + + final Finder title = find.byType(Text).first; + final double collapsedWidth = tester.getRect(title).width; + + // We drag down to fully expand the space bar. + await tester.drag(find.text('Item 2'), const Offset(0, 600.0)); + await tester.pumpAndSettle(); + + // The title is shifted by this margin to maintain the position of the + // bottom edge. + const double bottomMargin = titleFontSize * (expandedTitleScale - 1); + + // The title is scaled and transformed to be 3 times bigger, when the + // FlexibleSpaceBar is fully expanded, thus we expect the width to be + // 3 times smaller than the full width. The height of the text is the same + // as the font size, with 40 dps bottom margin to maintain its bottom position. + expect( + tester.getRect(title), + Rect.fromLTRB( + 0, + height - titleFontSize - bottomMargin, + (collapsedWidth / 3).floorToDouble(), + height - bottomMargin, + ), + ); + }); + testWidgets('FlexibleSpaceBar test titlePadding defaults', (WidgetTester tester) async { Widget buildFrame(TargetPlatform platform, bool? centerTitle) { return MaterialApp(