mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[AppBarTheme] adds titleSpacing parameter (#67105)
* adds titleSpacing in AppBarTheme Co-authored-by: Shi-Hao Hong <shihaohong@google.com>
This commit is contained in:
parent
731374016b
commit
a67ba2a2ba
@ -203,7 +203,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.primary = true,
|
||||
this.centerTitle,
|
||||
this.excludeHeaderSemantics = false,
|
||||
this.titleSpacing = NavigationToolbar.kMiddleSpacing,
|
||||
this.titleSpacing,
|
||||
this.toolbarOpacity = 1.0,
|
||||
this.bottomOpacity = 1.0,
|
||||
this.toolbarHeight,
|
||||
@ -211,7 +211,6 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
}) : assert(automaticallyImplyLeading != null),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
assert(primary != null),
|
||||
assert(titleSpacing != null),
|
||||
assert(toolbarOpacity != null),
|
||||
assert(bottomOpacity != null),
|
||||
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize.height ?? 0.0)),
|
||||
@ -424,7 +423,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
/// [title] to take all the space available, set this value to 0.0.
|
||||
///
|
||||
/// Defaults to [NavigationToolbar.kMiddleSpacing].
|
||||
final double titleSpacing;
|
||||
final double? titleSpacing;
|
||||
|
||||
/// How opaque the toolbar part of the app bar is.
|
||||
///
|
||||
@ -634,7 +633,7 @@ class _AppBarState extends State<AppBar> {
|
||||
middle: title,
|
||||
trailing: actions,
|
||||
centerMiddle: widget._getEffectiveCenterTitle(theme!),
|
||||
middleSpacing: widget.titleSpacing,
|
||||
middleSpacing: widget.titleSpacing ?? appBarTheme.titleSpacing ?? NavigationToolbar.kMiddleSpacing,
|
||||
);
|
||||
|
||||
// If the toolbar is allocated less than toolbarHeight make it
|
||||
@ -848,7 +847,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||
final bool primary;
|
||||
final bool? centerTitle;
|
||||
final bool excludeHeaderSemantics;
|
||||
final double titleSpacing;
|
||||
final double? titleSpacing;
|
||||
final double? expandedHeight;
|
||||
final double collapsedHeight;
|
||||
final double topPadding;
|
||||
@ -1064,7 +1063,7 @@ class SliverAppBar extends StatefulWidget {
|
||||
this.primary = true,
|
||||
this.centerTitle,
|
||||
this.excludeHeaderSemantics = false,
|
||||
this.titleSpacing = NavigationToolbar.kMiddleSpacing,
|
||||
this.titleSpacing,
|
||||
this.collapsedHeight,
|
||||
this.expandedHeight,
|
||||
this.floating = false,
|
||||
@ -1079,7 +1078,6 @@ class SliverAppBar extends StatefulWidget {
|
||||
}) : assert(automaticallyImplyLeading != null),
|
||||
assert(forceElevated != null),
|
||||
assert(primary != null),
|
||||
assert(titleSpacing != null),
|
||||
assert(floating != null),
|
||||
assert(pinned != null),
|
||||
assert(snap != null),
|
||||
@ -1259,7 +1257,7 @@ class SliverAppBar extends StatefulWidget {
|
||||
/// [title] to take all the space available, set this value to 0.0.
|
||||
///
|
||||
/// Defaults to [NavigationToolbar.kMiddleSpacing].
|
||||
final double titleSpacing;
|
||||
final double? titleSpacing;
|
||||
|
||||
/// Defines the height of the app bar when it is collapsed.
|
||||
///
|
||||
|
||||
@ -39,6 +39,7 @@ class AppBarTheme with Diagnosticable {
|
||||
this.actionsIconTheme,
|
||||
this.textTheme,
|
||||
this.centerTitle,
|
||||
this.titleSpacing,
|
||||
});
|
||||
|
||||
/// Default value for [AppBar.brightness].
|
||||
@ -81,6 +82,11 @@ class AppBarTheme with Diagnosticable {
|
||||
/// If null, the value is adapted to current [TargetPlatform].
|
||||
final bool? centerTitle;
|
||||
|
||||
/// Default value for [AppBar.titleSpacing].
|
||||
///
|
||||
/// If null, [AppBar] uses default value of [NavigationToolbar.kMiddleSpacing].
|
||||
final double? titleSpacing;
|
||||
|
||||
/// Creates a copy of this object with the given fields replaced with the
|
||||
/// new values.
|
||||
AppBarTheme copyWith({
|
||||
@ -92,6 +98,7 @@ class AppBarTheme with Diagnosticable {
|
||||
IconThemeData? iconTheme,
|
||||
TextTheme? textTheme,
|
||||
bool? centerTitle,
|
||||
double? titleSpacing,
|
||||
}) {
|
||||
return AppBarTheme(
|
||||
brightness: brightness ?? this.brightness,
|
||||
@ -102,6 +109,7 @@ class AppBarTheme with Diagnosticable {
|
||||
actionsIconTheme: actionsIconTheme ?? this.actionsIconTheme,
|
||||
textTheme: textTheme ?? this.textTheme,
|
||||
centerTitle: centerTitle ?? this.centerTitle,
|
||||
titleSpacing: titleSpacing ?? this.titleSpacing,
|
||||
);
|
||||
}
|
||||
|
||||
@ -126,6 +134,7 @@ class AppBarTheme with Diagnosticable {
|
||||
actionsIconTheme: IconThemeData.lerp(a?.actionsIconTheme, b?.actionsIconTheme, t),
|
||||
textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t),
|
||||
centerTitle: t < 0.5 ? a?.centerTitle : b?.centerTitle,
|
||||
titleSpacing: lerpDouble(a?.titleSpacing, b?.titleSpacing, t),
|
||||
);
|
||||
}
|
||||
|
||||
@ -140,6 +149,7 @@ class AppBarTheme with Diagnosticable {
|
||||
actionsIconTheme,
|
||||
textTheme,
|
||||
centerTitle,
|
||||
titleSpacing,
|
||||
);
|
||||
}
|
||||
|
||||
@ -157,7 +167,8 @@ class AppBarTheme with Diagnosticable {
|
||||
&& other.iconTheme == iconTheme
|
||||
&& other.actionsIconTheme == actionsIconTheme
|
||||
&& other.textTheme == textTheme
|
||||
&& other.centerTitle == centerTitle;
|
||||
&& other.centerTitle == centerTitle
|
||||
&& other.titleSpacing == titleSpacing;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -171,5 +182,6 @@ class AppBarTheme with Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<IconThemeData>('actionsIconTheme', actionsIconTheme, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<bool>('centerTitle', centerTitle, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<double>('titleSpacing', titleSpacing, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2211,4 +2211,27 @@ void main() {
|
||||
NavigationToolbar getAppBarWidget(Finder finder) => tester.widget<NavigationToolbar>(finder);
|
||||
expect(getAppBarWidget(appBarFinder).leading, null);
|
||||
});
|
||||
|
||||
testWidgets('AppBar.titleSpacing defaults to NavigationToolbar.kMiddleSpacing', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Title'),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
|
||||
expect(navToolBar.middleSpacing, NavigationToolbar.kMiddleSpacing);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.titleSpacing defaults to NavigationToolbar.kMiddleSpacing', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(buildSliverAppBarApp(
|
||||
floating: false,
|
||||
pinned: false,
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
|
||||
expect(navToolBar.middleSpacing, NavigationToolbar.kMiddleSpacing);
|
||||
});
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
@ -245,6 +246,116 @@ void main() {
|
||||
// The AppBar.shadowColor should be used instead of AppBarTheme.shadowColor.
|
||||
expect(appBar.shadowColor, Colors.yellow);
|
||||
});
|
||||
|
||||
testWidgets('AppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async {
|
||||
const double kTitleSpacing = 10;
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)),
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Title'),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
|
||||
expect(navToolBar.middleSpacing, kTitleSpacing);
|
||||
});
|
||||
|
||||
testWidgets('AppBar.titleSpacing takes priority over AppBarTheme.titleSpacing', (WidgetTester tester) async {
|
||||
const double kTitleSpacing = 10;
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)),
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Title'),
|
||||
titleSpacing: 40,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
|
||||
expect(navToolBar.middleSpacing, 40);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async {
|
||||
const double kTitleSpacing = 10;
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)),
|
||||
home: const CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverAppBar(
|
||||
title: Text('Title'),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
|
||||
expect(navToolBar.middleSpacing, kTitleSpacing);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.titleSpacing takes priority over AppBarTheme.titleSpacing ', (WidgetTester tester) async {
|
||||
const double kTitleSpacing = 10;
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)),
|
||||
home: const CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverAppBar(
|
||||
title: Text('Title'),
|
||||
titleSpacing: 40,
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolbar = tester.widget(find.byType(NavigationToolbar));
|
||||
expect(navToolbar.middleSpacing, 40);
|
||||
});
|
||||
|
||||
testWidgets('Default AppBarTheme debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
const AppBarTheme().debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description, <String>[]);
|
||||
});
|
||||
|
||||
testWidgets('AppBarTheme implements debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
const AppBarTheme(
|
||||
brightness: Brightness.dark,
|
||||
color: Color(0xff000001),
|
||||
elevation: 8.0,
|
||||
shadowColor: Color(0xff000002),
|
||||
centerTitle: true,
|
||||
titleSpacing: 40.0,
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description, <String>[
|
||||
'brightness: Brightness.dark',
|
||||
'color: Color(0xff000001)',
|
||||
'elevation: 8.0',
|
||||
'shadowColor: Color(0xff000002)',
|
||||
'centerTitle: true',
|
||||
'titleSpacing: 40.0',
|
||||
]);
|
||||
|
||||
// On the web, Dart doubles and ints are backed by the same kind of object because
|
||||
// JavaScript does not support integers. So, the Dart double "4.0" is identical
|
||||
// to "4", which results in the web evaluating to the value "4" regardless of which
|
||||
// one is used. This results in a difference for doubles in debugFillProperties between
|
||||
// the web and the rest of Flutter's target platforms.
|
||||
}, skip: kIsWeb);
|
||||
}
|
||||
|
||||
AppBarTheme _appBarTheme() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user