[Material] Add clip property to bottom sheet and theme (#38831)
This commit is contained in:
parent
36e8b93d1c
commit
6a5d32962c
@ -60,6 +60,7 @@ class BottomSheet extends StatefulWidget {
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.clipBehavior,
|
||||
@required this.onClosing,
|
||||
@required this.builder,
|
||||
}) : assert(enableDrag != null),
|
||||
@ -115,6 +116,19 @@ class BottomSheet extends StatefulWidget {
|
||||
/// Defaults to null and falls back to [Material]'s default.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
///
|
||||
/// Defines the bottom sheet's [Material.clipBehavior].
|
||||
///
|
||||
/// Use this property to enable clipping of content when the bottom sheet has
|
||||
/// a custom [shape] and the content can extend past this shape. For example,
|
||||
/// a bottom sheet with rounded corners and an edge-to-edge [Image] at the
|
||||
/// top.
|
||||
///
|
||||
/// If this property is null then [ThemeData.bottomSheetTheme.clipBehavior] is
|
||||
/// used. If that's null then the behavior will be [Clip.none].
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
_BottomSheetState createState() => _BottomSheetState();
|
||||
|
||||
@ -185,12 +199,14 @@ class _BottomSheetState extends State<BottomSheet> {
|
||||
final Color color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor;
|
||||
final double elevation = widget.elevation ?? bottomSheetTheme.elevation ?? 0;
|
||||
final ShapeBorder shape = widget.shape ?? bottomSheetTheme.shape;
|
||||
final Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none;
|
||||
|
||||
final Widget bottomSheet = Material(
|
||||
key: _childKey,
|
||||
color: color,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
child: NotificationListener<DraggableScrollableNotification>(
|
||||
onNotification: extentChanged,
|
||||
child: widget.builder(context),
|
||||
@ -247,6 +263,7 @@ class _ModalBottomSheet<T> extends StatefulWidget {
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.clipBehavior,
|
||||
this.isScrollControlled = false,
|
||||
}) : assert(isScrollControlled != null),
|
||||
super(key: key);
|
||||
@ -256,6 +273,7 @@ class _ModalBottomSheet<T> extends StatefulWidget {
|
||||
final Color backgroundColor;
|
||||
final double elevation;
|
||||
final ShapeBorder shape;
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
_ModalBottomSheetState<T> createState() => _ModalBottomSheetState<T>();
|
||||
@ -306,6 +324,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
||||
backgroundColor: widget.backgroundColor,
|
||||
elevation: widget.elevation,
|
||||
shape: widget.shape,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -323,6 +342,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.clipBehavior,
|
||||
@required this.isScrollControlled,
|
||||
RouteSettings settings,
|
||||
}) : assert(isScrollControlled != null),
|
||||
@ -334,6 +354,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||
final Color backgroundColor;
|
||||
final double elevation;
|
||||
final ShapeBorder shape;
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
Duration get transitionDuration => _bottomSheetDuration;
|
||||
@ -369,6 +390,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
isScrollControlled: isScrollControlled
|
||||
),
|
||||
);
|
||||
@ -423,6 +445,7 @@ Future<T> showModalBottomSheet<T>({
|
||||
Color backgroundColor,
|
||||
double elevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
bool isScrollControlled = false,
|
||||
bool useRootNavigator = false,
|
||||
}) {
|
||||
@ -441,6 +464,7 @@ Future<T> showModalBottomSheet<T>({
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
));
|
||||
}
|
||||
|
||||
@ -485,6 +509,7 @@ PersistentBottomSheetController<T> showBottomSheet<T>({
|
||||
Color backgroundColor,
|
||||
double elevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
}) {
|
||||
assert(context != null);
|
||||
assert(builder != null);
|
||||
@ -495,5 +520,6 @@ PersistentBottomSheetController<T> showBottomSheet<T>({
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ class BottomSheetThemeData extends Diagnosticable {
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.clipBehavior,
|
||||
});
|
||||
|
||||
/// Default value for [BottomSheet.backgroundColor].
|
||||
@ -50,17 +51,24 @@ class BottomSheetThemeData extends Diagnosticable {
|
||||
/// [BottomSheet] is rectangular.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// Default value for [BottomSheet.clipBehavior].
|
||||
///
|
||||
/// If null, [BottomSheet] uses [Clip.none].
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// Creates a copy of this object with the given fields replaced with the
|
||||
/// new values.
|
||||
BottomSheetThemeData copyWith({
|
||||
Color backgroundColor,
|
||||
double elevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
}) {
|
||||
return BottomSheetThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
elevation: elevation ?? this.elevation,
|
||||
shape: shape ?? this.shape,
|
||||
clipBehavior: clipBehavior ?? this.clipBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
@ -77,6 +85,7 @@ class BottomSheetThemeData extends Diagnosticable {
|
||||
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
||||
elevation: lerpDouble(a?.elevation, b?.elevation, t),
|
||||
shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
|
||||
clipBehavior: t < 0.5 ? a?.clipBehavior : b?.clipBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
@ -86,6 +95,7 @@ class BottomSheetThemeData extends Diagnosticable {
|
||||
backgroundColor,
|
||||
elevation,
|
||||
shape,
|
||||
clipBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
@ -98,7 +108,8 @@ class BottomSheetThemeData extends Diagnosticable {
|
||||
final BottomSheetThemeData typedOther = other;
|
||||
return typedOther.backgroundColor == backgroundColor
|
||||
&& typedOther.elevation == elevation
|
||||
&& typedOther.shape == shape;
|
||||
&& typedOther.shape == shape
|
||||
&& typedOther.clipBehavior == clipBehavior;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -107,5 +118,6 @@ class BottomSheetThemeData extends Diagnosticable {
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
|
||||
properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
@ -1622,6 +1622,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
Color backgroundColor,
|
||||
double elevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
}) {
|
||||
assert(() {
|
||||
if (widget.bottomSheet != null && isPersistent && _currentBottomSheet != null) {
|
||||
@ -1702,6 +1703,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
|
||||
if (!isPersistent)
|
||||
@ -1759,6 +1761,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
Color backgroundColor,
|
||||
double elevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
}) {
|
||||
assert(() {
|
||||
if (widget.bottomSheet != null) {
|
||||
@ -1782,6 +1785,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
});
|
||||
return _currentBottomSheet;
|
||||
@ -2313,6 +2317,7 @@ class _StandardBottomSheet extends StatefulWidget {
|
||||
this.backgroundColor,
|
||||
this.elevation,
|
||||
this.shape,
|
||||
this.clipBehavior,
|
||||
}) : super(key: key);
|
||||
|
||||
final AnimationController animationController; // we control it, but it must be disposed by whoever created it.
|
||||
@ -2324,6 +2329,7 @@ class _StandardBottomSheet extends StatefulWidget {
|
||||
final Color backgroundColor;
|
||||
final double elevation;
|
||||
final ShapeBorder shape;
|
||||
final Clip clipBehavior;
|
||||
|
||||
@override
|
||||
_StandardBottomSheetState createState() => _StandardBottomSheetState();
|
||||
@ -2412,6 +2418,7 @@ class _StandardBottomSheetState extends State<_StandardBottomSheet> {
|
||||
backgroundColor: widget.backgroundColor,
|
||||
elevation: widget.elevation,
|
||||
shape: widget.shape,
|
||||
clipBehavior: widget.clipBehavior,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -270,6 +270,7 @@ void main() {
|
||||
const Color color = Colors.pink;
|
||||
const double elevation = 9.0;
|
||||
final ShapeBorder shape = BeveledRectangleBorder(borderRadius: BorderRadius.circular(12));
|
||||
const Clip clipBehavior = Clip.antiAlias;
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
@ -283,6 +284,7 @@ void main() {
|
||||
backgroundColor: color,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
builder: (BuildContext context) {
|
||||
return Container(
|
||||
child: const Text('BottomSheet'),
|
||||
@ -297,6 +299,7 @@ void main() {
|
||||
expect(bottomSheet.backgroundColor, color);
|
||||
expect(bottomSheet.elevation, elevation);
|
||||
expect(bottomSheet.shape, shape);
|
||||
expect(bottomSheet.clipBehavior, clipBehavior);
|
||||
});
|
||||
|
||||
testWidgets('modal BottomSheet with scrollController has semantics', (WidgetTester tester) async {
|
||||
|
@ -17,6 +17,7 @@ void main() {
|
||||
expect(bottomSheetTheme.backgroundColor, null);
|
||||
expect(bottomSheetTheme.elevation, null);
|
||||
expect(bottomSheetTheme.shape, null);
|
||||
expect(bottomSheetTheme.clipBehavior, null);
|
||||
});
|
||||
|
||||
testWidgets('Default BottomSheetThemeData debugFillProperties', (WidgetTester tester) async {
|
||||
@ -37,6 +38,7 @@ void main() {
|
||||
backgroundColor: const Color(0xFFFFFFFF),
|
||||
elevation: 2.0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0)),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
@ -48,6 +50,7 @@ void main() {
|
||||
'backgroundColor: Color(0xffffffff)',
|
||||
'elevation: 2.0',
|
||||
'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))',
|
||||
'clipBehavior: Clip.antiAlias'
|
||||
]);
|
||||
});
|
||||
|
||||
@ -72,6 +75,7 @@ void main() {
|
||||
expect(material.color, null);
|
||||
expect(material.elevation, 0.0);
|
||||
expect(material.shape, null);
|
||||
expect(material.clipBehavior, Clip.none);
|
||||
});
|
||||
|
||||
testWidgets('BottomSheet uses values from BottomSheetThemeData', (WidgetTester tester) async {
|
||||
@ -98,6 +102,7 @@ void main() {
|
||||
expect(material.color, bottomSheetTheme.backgroundColor);
|
||||
expect(material.elevation, bottomSheetTheme.elevation);
|
||||
expect(material.shape, bottomSheetTheme.shape);
|
||||
expect(material.clipBehavior, bottomSheetTheme.clipBehavior);
|
||||
});
|
||||
|
||||
testWidgets('BottomSheet widget properties take priority over theme', (WidgetTester tester) async {
|
||||
@ -106,6 +111,7 @@ void main() {
|
||||
const ShapeBorder shape = RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(9.0)),
|
||||
);
|
||||
const Clip clipBehavior = Clip.hardEdge;
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(bottomSheetTheme: _bottomSheetTheme()),
|
||||
@ -114,6 +120,7 @@ void main() {
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
shape: shape,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
onClosing: () {},
|
||||
builder: (BuildContext context) {
|
||||
return Container();
|
||||
@ -131,6 +138,7 @@ void main() {
|
||||
expect(material.color, backgroundColor);
|
||||
expect(material.elevation, elevation);
|
||||
expect(material.shape, shape);
|
||||
expect(material.clipBehavior, clipBehavior);
|
||||
});
|
||||
}
|
||||
|
||||
@ -139,5 +147,6 @@ BottomSheetThemeData _bottomSheetTheme() {
|
||||
backgroundColor: Colors.orange,
|
||||
elevation: 12.0,
|
||||
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
);
|
||||
}
|
||||
|
@ -431,6 +431,7 @@ void main() {
|
||||
const Color color = Colors.pink;
|
||||
const double elevation = 9.0;
|
||||
final ShapeBorder shape = BeveledRectangleBorder(borderRadius: BorderRadius.circular(12));
|
||||
const Clip clipBehavior = Clip.antiAlias;
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
@ -449,7 +450,7 @@ void main() {
|
||||
Container(height: 100.0, child: const Text('Three')),
|
||||
],
|
||||
);
|
||||
}, backgroundColor: color, elevation: elevation, shape: shape);
|
||||
}, backgroundColor: color, elevation: elevation, shape: shape, clipBehavior: clipBehavior);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
@ -457,6 +458,7 @@ void main() {
|
||||
expect(bottomSheet.backgroundColor, color);
|
||||
expect(bottomSheet.elevation, elevation);
|
||||
expect(bottomSheet.shape, shape);
|
||||
expect(bottomSheet.clipBehavior, clipBehavior);
|
||||
});
|
||||
|
||||
testWidgets('PersistentBottomSheetController.close dismisses the bottom sheet', (WidgetTester tester) async {
|
||||
|
Loading…
x
Reference in New Issue
Block a user