Unverified Commit db89df51 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

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 

![Screenshot 2023-08-15 at 18 11 34](https://github.com/flutter/flutter/assets/48603081/4b798998-8549-43aa-b564-933ea14f494c)

### After

![Screenshot 2023-08-15 at 18 11 45](https://github.com/flutter/flutter/assets/48603081/b085a33a-db7d-40d4-8a12-ee37197b5bd4)
parent 0283d8a8
...@@ -1261,6 +1261,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -1261,6 +1261,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
currentExtent: math.max(minExtent, maxExtent - shrinkOffset), currentExtent: math.max(minExtent, maxExtent - shrinkOffset),
toolbarOpacity: toolbarOpacity, toolbarOpacity: toolbarOpacity,
isScrolledUnder: isScrolledUnder, isScrolledUnder: isScrolledUnder,
hasLeading: leading != null || automaticallyImplyLeading,
child: AppBar( child: AppBar(
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
leading: leading, leading: leading,
......
...@@ -156,6 +156,7 @@ class FlexibleSpaceBar extends StatefulWidget { ...@@ -156,6 +156,7 @@ class FlexibleSpaceBar extends StatefulWidget {
double? minExtent, double? minExtent,
double? maxExtent, double? maxExtent,
bool? isScrolledUnder, bool? isScrolledUnder,
bool? hasLeading,
required double currentExtent, required double currentExtent,
required Widget child, required Widget child,
}) { }) {
...@@ -164,6 +165,7 @@ class FlexibleSpaceBar extends StatefulWidget { ...@@ -164,6 +165,7 @@ class FlexibleSpaceBar extends StatefulWidget {
minExtent: minExtent ?? currentExtent, minExtent: minExtent ?? currentExtent,
maxExtent: maxExtent ?? currentExtent, maxExtent: maxExtent ?? currentExtent,
isScrolledUnder: isScrolledUnder, isScrolledUnder: isScrolledUnder,
hasLeading: hasLeading,
currentExtent: currentExtent, currentExtent: currentExtent,
child: child, child: child,
); );
...@@ -321,7 +323,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> { ...@@ -321,7 +323,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme); final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
final EdgeInsetsGeometry padding = widget.titlePadding ?? final EdgeInsetsGeometry padding = widget.titlePadding ??
EdgeInsetsDirectional.only( EdgeInsetsDirectional.only(
start: effectiveCenterTitle ? 0.0 : 72.0, start: effectiveCenterTitle && !(settings.hasLeading ?? false) ? 0.0 : 72.0,
bottom: 16.0, bottom: 16.0,
); );
final double scaleValue = Tween<double>(begin: widget.expandedTitleScale, end: 1.0).transform(t); final double scaleValue = Tween<double>(begin: widget.expandedTitleScale, end: 1.0).transform(t);
...@@ -380,6 +382,7 @@ class FlexibleSpaceBarSettings extends InheritedWidget { ...@@ -380,6 +382,7 @@ class FlexibleSpaceBarSettings extends InheritedWidget {
required this.currentExtent, required this.currentExtent,
required super.child, required super.child,
this.isScrolledUnder, this.isScrolledUnder,
this.hasLeading,
}) : assert(minExtent >= 0), }) : assert(minExtent >= 0),
assert(maxExtent >= 0), assert(maxExtent >= 0),
assert(currentExtent >= 0), assert(currentExtent >= 0),
...@@ -413,13 +416,24 @@ class FlexibleSpaceBarSettings extends InheritedWidget { ...@@ -413,13 +416,24 @@ class FlexibleSpaceBarSettings extends InheritedWidget {
/// overlaps the primary scrollable's contents. /// overlaps the primary scrollable's contents.
final bool? isScrolledUnder; 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 @override
bool updateShouldNotify(FlexibleSpaceBarSettings oldWidget) { bool updateShouldNotify(FlexibleSpaceBarSettings oldWidget) {
return toolbarOpacity != oldWidget.toolbarOpacity return toolbarOpacity != oldWidget.toolbarOpacity
|| minExtent != oldWidget.minExtent || minExtent != oldWidget.minExtent
|| maxExtent != oldWidget.maxExtent || maxExtent != oldWidget.maxExtent
|| currentExtent != oldWidget.currentExtent || currentExtent != oldWidget.currentExtent
|| isScrolledUnder != oldWidget.isScrolledUnder; || isScrolledUnder != oldWidget.isScrolledUnder
|| hasLeading != oldWidget.hasLeading;
} }
} }
......
...@@ -821,6 +821,94 @@ void main() { ...@@ -821,6 +821,94 @@ void main() {
expect(RenderRebuildTracker.count, greaterThan(1)); expect(RenderRebuildTracker.count, greaterThan(1));
expect(tester.layers.whereType<OpacityLayer>(), isEmpty); 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 { class TestDelegate extends SliverPersistentHeaderDelegate {
......
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