Unverified Commit 6a5d3296 authored by rami-a's avatar rami-a Committed by GitHub

[Material] Add clip property to bottom sheet and theme (#38831)

parent 36e8b93d
......@@ -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 {
......
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