Fix FlexibleSpaceBar.title
doesn't respect the leading widget (#132573)
fixes [Long `FlexibleSpaceBar.title` doesn't respect the leading widget ](https://github.com/flutter/flutter/issues/132030) ### Description - This adds `FlexibleSpaceBarSettings.hasLeading` for the `FlexibleSpaceBar`'s title to respect the leading widget. - Use the new `FlexibleSpaceBarSettings.hasLeading` property in the `SliverAppBar` for its `FlexibleSpaceBar`. ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, brightness: Brightness.dark, ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('TargetPlatform.Android'), Theme( data: Theme.of(context).copyWith( platform: TargetPlatform.android, ), child: Container( height: 250, padding: const EdgeInsets.all(8), decoration: BoxDecoration( border: Border.all( color: Colors.amber, width: 4, ), ), child: const AppBarLeading( showLeading: true, showTitle: false, ), ), ), const Text('TargetPlatform.iOS'), Theme( data: Theme.of(context).copyWith( platform: TargetPlatform.iOS, ), child: Container( height: 250, padding: const EdgeInsets.all(8), decoration: BoxDecoration( border: Border.all( color: Colors.amber, width: 2, ), ), child: const AppBarLeading( showLeading: true, showTitle: false, ), ), ), ], ), ); } } class AppBarLeading extends StatelessWidget { const AppBarLeading({ super.key, required this.showLeading, required this.showTitle, }); final bool showLeading; final bool showTitle; @override Widget build(BuildContext context) { return Scaffold( drawer: const Drawer(), body: CustomScrollView( slivers: [ SliverAppBar( automaticallyImplyLeading: showLeading, iconTheme: const IconThemeData( color: Colors.amber, ), title: showTitle ? const Text('AppBar') : null, flexibleSpace: FlexibleSpaceBar( title: Text('Title ' * 15), // centerTitle: true, ), toolbarHeight: showTitle ? 170 : 100, ), ], ), ); } } ``` </details> ### Before  ### After 
This commit is contained in:
parent
0283d8a8d0
commit
db89df51c3
@ -1261,6 +1261,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||
currentExtent: math.max(minExtent, maxExtent - shrinkOffset),
|
||||
toolbarOpacity: toolbarOpacity,
|
||||
isScrolledUnder: isScrolledUnder,
|
||||
hasLeading: leading != null || automaticallyImplyLeading,
|
||||
child: AppBar(
|
||||
clipBehavior: clipBehavior,
|
||||
leading: leading,
|
||||
|
@ -156,6 +156,7 @@ class FlexibleSpaceBar extends StatefulWidget {
|
||||
double? minExtent,
|
||||
double? maxExtent,
|
||||
bool? isScrolledUnder,
|
||||
bool? hasLeading,
|
||||
required double currentExtent,
|
||||
required Widget child,
|
||||
}) {
|
||||
@ -164,6 +165,7 @@ class FlexibleSpaceBar extends StatefulWidget {
|
||||
minExtent: minExtent ?? currentExtent,
|
||||
maxExtent: maxExtent ?? currentExtent,
|
||||
isScrolledUnder: isScrolledUnder,
|
||||
hasLeading: hasLeading,
|
||||
currentExtent: currentExtent,
|
||||
child: child,
|
||||
);
|
||||
@ -321,7 +323,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
|
||||
final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
|
||||
final EdgeInsetsGeometry padding = widget.titlePadding ??
|
||||
EdgeInsetsDirectional.only(
|
||||
start: effectiveCenterTitle ? 0.0 : 72.0,
|
||||
start: effectiveCenterTitle && !(settings.hasLeading ?? false) ? 0.0 : 72.0,
|
||||
bottom: 16.0,
|
||||
);
|
||||
final double scaleValue = Tween<double>(begin: widget.expandedTitleScale, end: 1.0).transform(t);
|
||||
@ -380,6 +382,7 @@ class FlexibleSpaceBarSettings extends InheritedWidget {
|
||||
required this.currentExtent,
|
||||
required super.child,
|
||||
this.isScrolledUnder,
|
||||
this.hasLeading,
|
||||
}) : assert(minExtent >= 0),
|
||||
assert(maxExtent >= 0),
|
||||
assert(currentExtent >= 0),
|
||||
@ -413,13 +416,24 @@ class FlexibleSpaceBarSettings extends InheritedWidget {
|
||||
/// overlaps the primary scrollable's contents.
|
||||
final bool? isScrolledUnder;
|
||||
|
||||
/// True if the FlexibleSpaceBar has a leading widget.
|
||||
///
|
||||
/// This value is used by the [FlexibleSpaceBar] to determine
|
||||
/// if there should be a gap between the leading widget and
|
||||
/// the title.
|
||||
///
|
||||
/// Null if the caller hasn't determined if the FlexibleSpaceBar
|
||||
/// has a leading widget.
|
||||
final bool? hasLeading;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(FlexibleSpaceBarSettings oldWidget) {
|
||||
return toolbarOpacity != oldWidget.toolbarOpacity
|
||||
|| minExtent != oldWidget.minExtent
|
||||
|| maxExtent != oldWidget.maxExtent
|
||||
|| currentExtent != oldWidget.currentExtent
|
||||
|| isScrolledUnder != oldWidget.isScrolledUnder;
|
||||
|| isScrolledUnder != oldWidget.isScrolledUnder
|
||||
|| hasLeading != oldWidget.hasLeading;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,6 +821,94 @@ void main() {
|
||||
expect(RenderRebuildTracker.count, greaterThan(1));
|
||||
expect(tester.layers.whereType<OpacityLayer>(), isEmpty);
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/132030.
|
||||
testWidgetsWithLeakTracking('FlexibleSpaceBarSettings.hasLeading provides a gap between leading and title', (WidgetTester tester) async {
|
||||
final FlexibleSpaceBarSettings customSettings = FlexibleSpaceBar.createSettings(
|
||||
currentExtent: 200.0,
|
||||
hasLeading: true,
|
||||
child: AppBar(
|
||||
leading: const Icon(Icons.menu),
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
title: Text('title ' * 10),
|
||||
centerTitle: true,
|
||||
),
|
||||
),
|
||||
) as FlexibleSpaceBarSettings;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverPersistentHeader(
|
||||
floating: true,
|
||||
pinned: true,
|
||||
delegate: TestDelegate(settings: customSettings),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 1200.0,
|
||||
color: Colors.orange[400],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getTopLeft(find.byType(Text)).dx, closeTo(72.0, 0.01));
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/132030.
|
||||
testWidgetsWithLeakTracking('Long centered FlexibleSpaceBar.title respects leading widget', (WidgetTester tester) async {
|
||||
// Test start position of a long title when the leading widget is
|
||||
// shown by default and the long title is centered.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
drawer: const Drawer(),
|
||||
body: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverAppBar(
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
title: Text('Title ' * 10),
|
||||
centerTitle: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tester.getTopLeft(find.byType(Text)).dx, 72.0);
|
||||
|
||||
// Test start position of a long title when the leading widget is provided
|
||||
// and the long title is centered.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverAppBar(
|
||||
leading: const Icon(Icons.menu),
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
title: Text('Title ' * 10),
|
||||
centerTitle: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getTopLeft(find.byType(Text)).dx, 72.0);
|
||||
});
|
||||
}
|
||||
|
||||
class TestDelegate extends SliverPersistentHeaderDelegate {
|
||||
|
Loading…
x
Reference in New Issue
Block a user