mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Add ability to customize drawer shape and color as well as theme drawer properties (#89237)
This commit is contained in:
parent
947034ed82
commit
069699ebde
@ -65,6 +65,7 @@ export 'src/material/divider.dart';
|
||||
export 'src/material/divider_theme.dart';
|
||||
export 'src/material/drawer.dart';
|
||||
export 'src/material/drawer_header.dart';
|
||||
export 'src/material/drawer_theme.dart';
|
||||
export 'src/material/dropdown.dart';
|
||||
export 'src/material/elevated_button.dart';
|
||||
export 'src/material/elevated_button_theme.dart';
|
||||
|
@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'debug.dart';
|
||||
import 'drawer_theme.dart';
|
||||
import 'list_tile.dart';
|
||||
import 'material.dart';
|
||||
import 'material_localizations.dart';
|
||||
@ -139,19 +140,36 @@ class Drawer extends StatelessWidget {
|
||||
/// The [elevation] must be non-negative.
|
||||
const Drawer({
|
||||
Key? key,
|
||||
this.elevation = 16.0,
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.child,
|
||||
this.semanticLabel,
|
||||
}) : assert(elevation != null && elevation >= 0.0),
|
||||
}) : assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
/// Sets the color of the [Material] that holds all of the [Drawer]'s
|
||||
/// contents.
|
||||
///
|
||||
/// If this is null, then [DrawerThemeData.backgroundColor] is used. If that
|
||||
/// is also null, then it falls back to [Material]'s default.
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// The z-coordinate at which to place this drawer relative to its parent.
|
||||
///
|
||||
/// This controls the size of the shadow below the drawer.
|
||||
///
|
||||
/// Defaults to 16, the appropriate elevation for drawers. The value is
|
||||
/// always non-negative.
|
||||
final double elevation;
|
||||
/// If this is null, then [DrawerThemeData.elevation] is used. If that
|
||||
/// is also null, then it defaults to 16.0.
|
||||
final double? elevation;
|
||||
|
||||
/// The shape of the drawer.
|
||||
///
|
||||
/// Defines the drawer's [Material.shape].
|
||||
///
|
||||
/// If this is null, then [DrawerThemeData.shape] is used. If that
|
||||
/// is also null, then it falls back to [Material]'s default.
|
||||
final ShapeBorder? shape;
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
@ -175,6 +193,7 @@ class Drawer extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
final DrawerThemeData drawerTheme = DrawerTheme.of(context);
|
||||
String? label = semanticLabel;
|
||||
switch (Theme.of(context).platform) {
|
||||
case TargetPlatform.iOS:
|
||||
@ -194,7 +213,9 @@ class Drawer extends StatelessWidget {
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.expand(width: _kWidth),
|
||||
child: Material(
|
||||
elevation: elevation,
|
||||
color: backgroundColor ?? drawerTheme.backgroundColor,
|
||||
elevation: elevation ?? drawerTheme.elevation ?? 16.0,
|
||||
shape: shape ?? drawerTheme.shape,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
@ -277,9 +298,11 @@ class DrawerController extends StatefulWidget {
|
||||
/// {@endtemplate}
|
||||
final DragStartBehavior dragStartBehavior;
|
||||
|
||||
/// The color to use for the scrim that obscures primary content while a drawer is open.
|
||||
/// The color to use for the scrim that obscures the underlying content while
|
||||
/// a drawer is open.
|
||||
///
|
||||
/// By default, the color used is [Colors.black54]
|
||||
/// If this is null, then [DrawerThemeData.scrimColor] is used. If that
|
||||
/// is also null, then it defaults to [Colors.black54].
|
||||
final Color? scrimColor;
|
||||
|
||||
/// Determines if the [Drawer] can be opened with a drag gesture.
|
||||
@ -317,7 +340,6 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrimColorTween = _buildScrimColorTween();
|
||||
_controller = AnimationController(
|
||||
value: widget.isDrawerOpen ? 1.0 : 0.0,
|
||||
duration: _kBaseSettleDuration,
|
||||
@ -335,6 +357,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_scrimColorTween = _buildScrimColorTween();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(DrawerController oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
@ -492,7 +520,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
|
||||
final GlobalKey _gestureDetectorKey = GlobalKey();
|
||||
|
||||
ColorTween _buildScrimColorTween() {
|
||||
return ColorTween(begin: Colors.transparent, end: widget.scrimColor ?? Colors.black54);
|
||||
return ColorTween(
|
||||
begin: Colors.transparent,
|
||||
end: widget.scrimColor
|
||||
?? DrawerTheme.of(context).scrimColor
|
||||
?? Colors.black54,
|
||||
);
|
||||
}
|
||||
|
||||
AlignmentDirectional get _drawerOuterAlignment {
|
||||
|
161
packages/flutter/lib/src/material/drawer_theme.dart
Normal file
161
packages/flutter/lib/src/material/drawer_theme.dart
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'theme.dart';
|
||||
|
||||
/// Defines default property values for descendant [Drawer] widgets.
|
||||
///
|
||||
/// Descendant widgets obtain the current [DrawerThemeData] object
|
||||
/// using `DrawerTheme.of(context)`. Instances of [DrawerThemeData] can be
|
||||
/// customized with [DrawerThemeData.copyWith].
|
||||
///
|
||||
/// Typically a [DrawerThemeData] is specified as part of the
|
||||
/// overall [Theme] with [ThemeData.drawerTheme].
|
||||
///
|
||||
/// All [DrawerThemeData] properties are `null` by default.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [DrawerTheme], an [InheritedWidget] that propagates the theme down its
|
||||
/// subtree.
|
||||
/// * [ThemeData], which describes the overall theme information for the
|
||||
/// application and can customize a drawer using [ThemeData.drawerTheme].
|
||||
@immutable
|
||||
class DrawerThemeData with Diagnosticable {
|
||||
/// Creates a theme that can be used for [ThemeData.drawerTheme] and
|
||||
/// [DrawerTheme].
|
||||
const DrawerThemeData({
|
||||
this.backgroundColor,
|
||||
this.scrimColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
});
|
||||
|
||||
/// Overrides the default value of [Drawer.backgroundColor].
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Overrides the default value of [DrawerController.scrimColor].
|
||||
final Color? scrimColor;
|
||||
|
||||
/// Overrides the default value of [Drawer.elevation].
|
||||
final double? elevation;
|
||||
|
||||
/// Overrides the default value of [Drawer.shape].
|
||||
final ShapeBorder? shape;
|
||||
|
||||
/// Creates a copy of this object with the given fields replaced with the
|
||||
/// new values.
|
||||
DrawerThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
Color? scrimColor,
|
||||
double? elevation,
|
||||
ShapeBorder? shape,
|
||||
}) {
|
||||
return DrawerThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
scrimColor: scrimColor ?? this.scrimColor,
|
||||
elevation: elevation ?? this.elevation,
|
||||
shape: shape ?? this.shape,
|
||||
);
|
||||
}
|
||||
|
||||
/// Linearly interpolate between two drawer themes.
|
||||
///
|
||||
/// If both arguments are null then null is returned.
|
||||
///
|
||||
/// {@macro dart.ui.shadow.lerp}
|
||||
static DrawerThemeData? lerp(DrawerThemeData? a, DrawerThemeData? b, double t) {
|
||||
assert(t != null);
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
return DrawerThemeData(
|
||||
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
||||
scrimColor: Color.lerp(a?.scrimColor, b?.scrimColor, t),
|
||||
elevation: lerpDouble(a?.elevation, b?.elevation, t),
|
||||
shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashValues(
|
||||
backgroundColor,
|
||||
scrimColor,
|
||||
elevation,
|
||||
shape,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
return other is DrawerThemeData
|
||||
&& other.backgroundColor == backgroundColor
|
||||
&& other.scrimColor == scrimColor
|
||||
&& other.elevation == elevation
|
||||
&& other.shape == shape;
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
|
||||
properties.add(ColorProperty('scrimColor', scrimColor, defaultValue: null));
|
||||
properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
/// An inherited widget that defines visual properties for [Drawer]s in this
|
||||
/// widget's subtree.
|
||||
///
|
||||
/// Values specified here are used for [Drawer] properties that are not
|
||||
/// given an explicit non-null value.
|
||||
///
|
||||
/// Using this would allow you to override the [ThemeData.drawerTheme].
|
||||
class DrawerTheme extends InheritedTheme {
|
||||
/// Creates a theme that defines the [DrawerThemeData] properties for a
|
||||
/// [Drawer].
|
||||
const DrawerTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : assert(data != null), super(key: key, child: child);
|
||||
|
||||
/// Specifies the background color, scrim color, elevation, and shape for
|
||||
/// descendant [Drawer] widgets.
|
||||
final DrawerThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [DrawerTheme] widget, then
|
||||
/// [ThemeData.drawerTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// DrawerTheme theme = DrawerTheme.of(context);
|
||||
/// ```
|
||||
static DrawerThemeData of(BuildContext context) {
|
||||
final DrawerTheme? drawerTheme = context.dependOnInheritedWidgetOfExactType<DrawerTheme>();
|
||||
return drawerTheme?.data ?? Theme.of(context).drawerTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) {
|
||||
return DrawerTheme(data: data, child: child);
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(DrawerTheme oldWidget) => data != oldWidget.data;
|
||||
}
|
@ -1619,7 +1619,8 @@ class Scaffold extends StatefulWidget {
|
||||
|
||||
/// The color to use for the scrim that obscures primary content while a drawer is open.
|
||||
///
|
||||
/// By default, the color is [Colors.black54]
|
||||
/// If this is null, then [DrawerThemeData.scrimColor] is used. If that
|
||||
/// is also null, then it defaults to [Colors.black54].
|
||||
final Color? drawerScrimColor;
|
||||
|
||||
/// The color of the [Material] widget that underlies the entire Scaffold.
|
||||
|
@ -22,6 +22,7 @@ import 'colors.dart';
|
||||
import 'data_table_theme.dart';
|
||||
import 'dialog_theme.dart';
|
||||
import 'divider_theme.dart';
|
||||
import 'drawer_theme.dart';
|
||||
import 'elevated_button_theme.dart';
|
||||
import 'floating_action_button_theme.dart';
|
||||
import 'ink_splash.dart';
|
||||
@ -336,6 +337,7 @@ class ThemeData with Diagnosticable {
|
||||
RadioThemeData? radioTheme,
|
||||
SwitchThemeData? switchTheme,
|
||||
ProgressIndicatorThemeData? progressIndicatorTheme,
|
||||
DrawerThemeData? drawerTheme,
|
||||
@Deprecated(
|
||||
'This "fix" is now enabled by default. '
|
||||
'This feature was deprecated after v2.5.0-1.0.pre.',
|
||||
@ -479,6 +481,7 @@ class ThemeData with Diagnosticable {
|
||||
radioTheme ??= const RadioThemeData();
|
||||
switchTheme ??= const SwitchThemeData();
|
||||
progressIndicatorTheme ??= const ProgressIndicatorThemeData();
|
||||
drawerTheme ??= const DrawerThemeData();
|
||||
|
||||
fixTextFieldOutlineLabel ??= true;
|
||||
useTextSelectionTheme ??= true;
|
||||
@ -560,6 +563,7 @@ class ThemeData with Diagnosticable {
|
||||
radioTheme: radioTheme,
|
||||
switchTheme: switchTheme,
|
||||
progressIndicatorTheme: progressIndicatorTheme,
|
||||
drawerTheme: drawerTheme,
|
||||
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel,
|
||||
useTextSelectionTheme: useTextSelectionTheme,
|
||||
androidOverscrollIndicator: androidOverscrollIndicator,
|
||||
@ -693,6 +697,7 @@ class ThemeData with Diagnosticable {
|
||||
required this.radioTheme,
|
||||
required this.switchTheme,
|
||||
required this.progressIndicatorTheme,
|
||||
required this.drawerTheme,
|
||||
@Deprecated(
|
||||
'This "fix" is now enabled by default. '
|
||||
'This feature was deprecated after v2.5.0-1.0.pre.',
|
||||
@ -777,6 +782,7 @@ class ThemeData with Diagnosticable {
|
||||
assert(radioTheme != null),
|
||||
assert(switchTheme != null),
|
||||
assert(progressIndicatorTheme != null),
|
||||
assert(drawerTheme != null),
|
||||
assert(fixTextFieldOutlineLabel != null),
|
||||
assert(useTextSelectionTheme != null);
|
||||
|
||||
@ -1337,6 +1343,9 @@ class ThemeData with Diagnosticable {
|
||||
/// A theme for customizing the appearance and layout of [ProgressIndicator] widgets.
|
||||
final ProgressIndicatorThemeData progressIndicatorTheme;
|
||||
|
||||
/// A theme for customizing the appearance and layout of [Drawer] widgets.
|
||||
final DrawerThemeData drawerTheme;
|
||||
|
||||
/// An obsolete flag to allow apps to opt-out of a
|
||||
/// [small fix](https://github.com/flutter/flutter/issues/54028) for the Y
|
||||
/// coordinate of the floating label in a [TextField] [OutlineInputBorder].
|
||||
@ -1496,6 +1505,7 @@ class ThemeData with Diagnosticable {
|
||||
RadioThemeData? radioTheme,
|
||||
SwitchThemeData? switchTheme,
|
||||
ProgressIndicatorThemeData? progressIndicatorTheme,
|
||||
DrawerThemeData? drawerTheme,
|
||||
@Deprecated(
|
||||
'This "fix" is now enabled by default. '
|
||||
'This feature was deprecated after v2.5.0-1.0.pre.',
|
||||
@ -1586,6 +1596,7 @@ class ThemeData with Diagnosticable {
|
||||
radioTheme: radioTheme ?? this.radioTheme,
|
||||
switchTheme: switchTheme ?? this.switchTheme,
|
||||
progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme,
|
||||
drawerTheme: drawerTheme ?? this.drawerTheme,
|
||||
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel,
|
||||
useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme,
|
||||
androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator,
|
||||
@ -1746,6 +1757,7 @@ class ThemeData with Diagnosticable {
|
||||
radioTheme: RadioThemeData.lerp(a.radioTheme, b.radioTheme, t),
|
||||
switchTheme: SwitchThemeData.lerp(a.switchTheme, b.switchTheme, t),
|
||||
progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!,
|
||||
drawerTheme: DrawerThemeData.lerp(a.drawerTheme, b.drawerTheme, t)!,
|
||||
fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel,
|
||||
useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme,
|
||||
androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator,
|
||||
@ -1834,6 +1846,7 @@ class ThemeData with Diagnosticable {
|
||||
&& other.radioTheme == radioTheme
|
||||
&& other.switchTheme == switchTheme
|
||||
&& other.progressIndicatorTheme == progressIndicatorTheme
|
||||
&& other.drawerTheme == drawerTheme
|
||||
&& other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel
|
||||
&& other.useTextSelectionTheme == useTextSelectionTheme
|
||||
&& other.androidOverscrollIndicator == androidOverscrollIndicator;
|
||||
@ -1921,6 +1934,7 @@ class ThemeData with Diagnosticable {
|
||||
radioTheme,
|
||||
switchTheme,
|
||||
progressIndicatorTheme,
|
||||
drawerTheme,
|
||||
fixTextFieldOutlineLabel,
|
||||
useTextSelectionTheme,
|
||||
androidOverscrollIndicator,
|
||||
@ -2006,6 +2020,7 @@ class ThemeData with Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<RadioThemeData>('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug));
|
||||
properties.add(DiagnosticsProperty<SwitchThemeData>('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug));
|
||||
properties.add(DiagnosticsProperty<ProgressIndicatorThemeData>('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug));
|
||||
properties.add(DiagnosticsProperty<DrawerThemeData>('drawerTheme', drawerTheme, defaultValue: defaultData.drawerTheme, level: DiagnosticLevel.debug));
|
||||
properties.add(EnumProperty<AndroidOverscrollIndicator>('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug));
|
||||
}
|
||||
}
|
||||
|
202
packages/flutter/test/material/drawer_theme_test.dart
Normal file
202
packages/flutter/test/material/drawer_theme_test.dart
Normal file
@ -0,0 +1,202 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('copyWith, ==, hashCode basics', () {
|
||||
expect(const DrawerThemeData(), const DrawerThemeData().copyWith());
|
||||
expect(const DrawerThemeData().hashCode, const DrawerThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
testWidgets('Default debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
const DrawerThemeData().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('Custom debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
DrawerThemeData(
|
||||
backgroundColor: const Color(0x00000099),
|
||||
scrimColor: const Color(0x00000098),
|
||||
elevation: 5.0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.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>[
|
||||
'backgroundColor: Color(0x00000099)',
|
||||
'scrimColor: Color(0x00000098)',
|
||||
'elevation: 5.0',
|
||||
'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))',
|
||||
]);
|
||||
});
|
||||
|
||||
testWidgets('Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
key: scaffoldKey,
|
||||
drawer: const Drawer(),
|
||||
),
|
||||
),
|
||||
);
|
||||
scaffoldKey.currentState!.openDrawer();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(_drawerMaterial(tester).color, null);
|
||||
expect(_drawerMaterial(tester).elevation, 16.0);
|
||||
expect(_drawerMaterial(tester).shape, null);
|
||||
expect(_scrim(tester).color, Colors.black54);
|
||||
});
|
||||
|
||||
testWidgets('DrawerThemeData values are used when no Drawer properties are specified', (WidgetTester tester) async {
|
||||
const Color backgroundColor = Color(0x00000001);
|
||||
const Color scrimColor = Color(0x00000002);
|
||||
const double elevation = 7.0;
|
||||
const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
|
||||
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
drawerTheme: const DrawerThemeData(
|
||||
backgroundColor: backgroundColor,
|
||||
scrimColor: scrimColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
),
|
||||
),
|
||||
home: Scaffold(
|
||||
key: scaffoldKey,
|
||||
drawer: const Drawer(),
|
||||
),
|
||||
),
|
||||
);
|
||||
scaffoldKey.currentState!.openDrawer();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(_drawerMaterial(tester).color, backgroundColor);
|
||||
expect(_drawerMaterial(tester).elevation, elevation);
|
||||
expect(_drawerMaterial(tester).shape, shape);
|
||||
expect(_scrim(tester).color, scrimColor);
|
||||
});
|
||||
|
||||
testWidgets('Drawer values take priority over DrawerThemeData values when both properties are specified', (WidgetTester tester) async {
|
||||
const Color backgroundColor = Color(0x00000001);
|
||||
const Color scrimColor = Color(0x00000002);
|
||||
const double elevation = 7.0;
|
||||
const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
|
||||
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
drawerTheme: const DrawerThemeData(
|
||||
backgroundColor: Color(0x00000003),
|
||||
scrimColor: Color(0x00000004),
|
||||
elevation: 13.0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(29.0))),
|
||||
),
|
||||
),
|
||||
home: Scaffold(
|
||||
key: scaffoldKey,
|
||||
drawerScrimColor: scrimColor,
|
||||
drawer: const Drawer(
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
scaffoldKey.currentState!.openDrawer();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(_drawerMaterial(tester).color, backgroundColor);
|
||||
expect(_drawerMaterial(tester).elevation, elevation);
|
||||
expect(_drawerMaterial(tester).shape, shape);
|
||||
expect(_scrim(tester).color, scrimColor);
|
||||
});
|
||||
|
||||
testWidgets('DrawerTheme values take priority over ThemeData.drawerTheme values when both properties are specified', (WidgetTester tester) async {
|
||||
const Color backgroundColor = Color(0x00000001);
|
||||
const Color scrimColor = Color(0x00000002);
|
||||
const double elevation = 7.0;
|
||||
const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
|
||||
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
drawerTheme: const DrawerThemeData(
|
||||
backgroundColor: Color(0x00000003),
|
||||
scrimColor: Color(0x00000004),
|
||||
elevation: 13.0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(29.0))),
|
||||
),
|
||||
),
|
||||
home: DrawerTheme(
|
||||
data: const DrawerThemeData(
|
||||
backgroundColor: backgroundColor,
|
||||
scrimColor: scrimColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
),
|
||||
child: Scaffold(
|
||||
key: scaffoldKey,
|
||||
drawer: const Drawer(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
scaffoldKey.currentState!.openDrawer();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(_drawerMaterial(tester).color, backgroundColor);
|
||||
expect(_drawerMaterial(tester).elevation, elevation);
|
||||
expect(_drawerMaterial(tester).shape, shape);
|
||||
expect(_scrim(tester).color, scrimColor);
|
||||
});
|
||||
}
|
||||
|
||||
Material _drawerMaterial(WidgetTester tester) {
|
||||
return tester.firstWidget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(Drawer),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// The scrim is a Container within a Semantics node labeled "Dismiss",
|
||||
// within a DrawerController.
|
||||
Container _scrim(WidgetTester tester) {
|
||||
return tester.widget<Container>(
|
||||
find.descendant(
|
||||
of: find.descendant(
|
||||
of: find.byType(DrawerController),
|
||||
matching: find.byWidgetPredicate((Widget widget) {
|
||||
return widget is Semantics
|
||||
&& widget.properties.label == 'Dismiss';
|
||||
}),
|
||||
),
|
||||
matching: find.byType(Container),
|
||||
),
|
||||
);
|
||||
}
|
@ -344,6 +344,7 @@ void main() {
|
||||
radioTheme: const RadioThemeData(),
|
||||
switchTheme: const SwitchThemeData(),
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(),
|
||||
drawerTheme: const DrawerThemeData(),
|
||||
fixTextFieldOutlineLabel: false,
|
||||
useTextSelectionTheme: false,
|
||||
androidOverscrollIndicator: null,
|
||||
@ -439,6 +440,7 @@ void main() {
|
||||
radioTheme: const RadioThemeData(),
|
||||
switchTheme: const SwitchThemeData(),
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(),
|
||||
drawerTheme: const DrawerThemeData(),
|
||||
fixTextFieldOutlineLabel: true,
|
||||
useTextSelectionTheme: true,
|
||||
androidOverscrollIndicator: AndroidOverscrollIndicator.stretch,
|
||||
@ -510,6 +512,12 @@ void main() {
|
||||
elevatedButtonTheme: otherTheme.elevatedButtonTheme,
|
||||
outlinedButtonTheme: otherTheme.outlinedButtonTheme,
|
||||
textSelectionTheme: otherTheme.textSelectionTheme,
|
||||
dataTableTheme: otherTheme.dataTableTheme,
|
||||
checkboxTheme: otherTheme.checkboxTheme,
|
||||
radioTheme: otherTheme.radioTheme,
|
||||
switchTheme: otherTheme.switchTheme,
|
||||
progressIndicatorTheme: otherTheme.progressIndicatorTheme,
|
||||
drawerTheme: otherTheme.drawerTheme,
|
||||
fixTextFieldOutlineLabel: otherTheme.fixTextFieldOutlineLabel,
|
||||
);
|
||||
|
||||
@ -578,6 +586,12 @@ void main() {
|
||||
expect(themeDataCopy.elevatedButtonTheme, equals(otherTheme.elevatedButtonTheme));
|
||||
expect(themeDataCopy.outlinedButtonTheme, equals(otherTheme.outlinedButtonTheme));
|
||||
expect(themeDataCopy.textSelectionTheme, equals(otherTheme.textSelectionTheme));
|
||||
expect(themeDataCopy.dataTableTheme, equals(otherTheme.dataTableTheme));
|
||||
expect(themeDataCopy.checkboxTheme, equals(otherTheme.checkboxTheme));
|
||||
expect(themeDataCopy.radioTheme, equals(otherTheme.radioTheme));
|
||||
expect(themeDataCopy.switchTheme, equals(otherTheme.switchTheme));
|
||||
expect(themeDataCopy.progressIndicatorTheme, equals(otherTheme.progressIndicatorTheme));
|
||||
expect(themeDataCopy.drawerTheme, equals(otherTheme.drawerTheme));
|
||||
expect(themeDataCopy.fixTextFieldOutlineLabel, equals(otherTheme.fixTextFieldOutlineLabel));
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user