Unverified Commit 9f374f12 authored by Alex Li's avatar Alex Li Committed by GitHub

🚀 Expose `scrollControlDisabledMaxHeightRatio` to the modal bottom sheet (#129688)

Adding the `scrollControlDisabledMaxHeightRatio` parameter for modal bottom sheet widgets, and using the default value `9.0 / 16.0` to avoid breaking.

Resolves #129690.
parent 300c5d82
......@@ -26,6 +26,7 @@ const Duration _bottomSheetExitDuration = Duration(milliseconds: 200);
const Curve _modalBottomSheetCurve = decelerateEasing;
const double _minFlingVelocity = 700.0;
const double _closeProgressThreshold = 0.5;
const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0;
/// A callback for when the user begins dragging the bottom sheet.
///
......@@ -471,24 +472,26 @@ class _DragHandle extends StatelessWidget {
}
class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget {
const _BottomSheetLayoutWithSizeListener({
required this.onChildSizeChanged,
required this.animationValue,
required this.isScrollControlled,
required this.onChildSizeChanged,
required this.scrollControlDisabledMaxHeightRatio,
super.child,
});
final _SizeChangeCallback<Size> onChildSizeChanged;
final double animationValue;
final bool isScrollControlled;
final _SizeChangeCallback<Size> onChildSizeChanged;
final double scrollControlDisabledMaxHeightRatio;
@override
_RenderBottomSheetLayoutWithSizeListener createRenderObject(BuildContext context) {
return _RenderBottomSheetLayoutWithSizeListener(
onChildSizeChanged: onChildSizeChanged,
animationValue: animationValue,
isScrollControlled: isScrollControlled,
onChildSizeChanged: onChildSizeChanged,
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
);
}
......@@ -497,6 +500,7 @@ class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget {
renderObject.onChildSizeChanged = onChildSizeChanged;
renderObject.animationValue = animationValue;
renderObject.isScrollControlled = isScrollControlled;
renderObject.scrollControlDisabledMaxHeightRatio = scrollControlDisabledMaxHeightRatio;
}
}
......@@ -506,9 +510,11 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox {
required _SizeChangeCallback<Size> onChildSizeChanged,
required double animationValue,
required bool isScrollControlled,
}) : _animationValue = animationValue,
required double scrollControlDisabledMaxHeightRatio,
}) : _onChildSizeChanged = onChildSizeChanged,
_animationValue = animationValue,
_isScrollControlled = isScrollControlled,
_onChildSizeChanged = onChildSizeChanged,
_scrollControlDisabledMaxHeightRatio = scrollControlDisabledMaxHeightRatio,
super(child);
Size _lastSize = Size.zero;
......@@ -546,6 +552,17 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox {
markNeedsLayout();
}
double get scrollControlDisabledMaxHeightRatio => _scrollControlDisabledMaxHeightRatio;
double _scrollControlDisabledMaxHeightRatio;
set scrollControlDisabledMaxHeightRatio(double newValue) {
if (_scrollControlDisabledMaxHeightRatio == newValue) {
return;
}
_scrollControlDisabledMaxHeightRatio = newValue;
markNeedsLayout();
}
Size _getSize(BoxConstraints constraints) {
return constraints.constrain(constraints.biggest);
}
......@@ -591,13 +608,13 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox {
return _getSize(constraints);
}
BoxConstraints _getConstraintsForChild(BoxConstraints constraints) {
BoxConstraints _getConstraintsForChild(BoxConstraints constraints) {
return BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
maxHeight: isScrollControlled
? constraints.maxHeight
: constraints.maxHeight * 9.0 / 16.0,
? constraints.maxHeight
: constraints.maxHeight * scrollControlDisabledMaxHeightRatio,
);
}
......@@ -634,12 +651,14 @@ class _ModalBottomSheet<T> extends StatefulWidget {
this.clipBehavior,
this.constraints,
this.isScrollControlled = false,
this.scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio,
this.enableDrag = true,
this.showDragHandle = false,
});
final ModalBottomSheetRoute<T> route;
final bool isScrollControlled;
final double scrollControlDisabledMaxHeightRatio;
final Color? backgroundColor;
final double? elevation;
final ShapeBorder? shape;
......@@ -730,6 +749,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
},
animationValue: animationValue,
isScrollControlled: widget.isScrollControlled,
scrollControlDisabledMaxHeightRatio: widget.scrollControlDisabledMaxHeightRatio,
child: child,
),
),
......@@ -815,6 +835,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
this.enableDrag = true,
this.showDragHandle,
required this.isScrollControlled,
this.scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio,
super.settings,
this.transitionAnimationController,
this.anchorPoint,
......@@ -842,6 +863,13 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
/// to have the bottom sheet be draggable.
final bool isScrollControlled;
/// The max height constraint ratio for the bottom sheet
/// when [isScrollControlled] set to false,
/// no ratio will be applied when [isScrollControlled] set to true.
///
/// Defaults to 9 / 16.
final double scrollControlDisabledMaxHeightRatio;
/// The bottom sheet's background color.
///
/// Defines the bottom sheet's [Material.color].
......@@ -1026,6 +1054,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
clipBehavior: clipBehavior,
constraints: constraints,
isScrollControlled: isScrollControlled,
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
enableDrag: enableDrag,
showDragHandle: showDragHandle ?? (enableDrag && (sheetTheme.showDragHandle ?? false)),
);
......@@ -1192,6 +1221,7 @@ Future<T?> showModalBottomSheet<T>({
BoxConstraints? constraints,
Color? barrierColor,
bool isScrollControlled = false,
double scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio,
bool useRootNavigator = false,
bool isDismissible = true,
bool enableDrag = true,
......@@ -1210,6 +1240,7 @@ Future<T?> showModalBottomSheet<T>({
builder: builder,
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
isScrollControlled: isScrollControlled,
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
barrierLabel: barrierLabel ?? localizations.scrimLabel,
barrierOnTapHint: localizations.scrimOnTapHint(localizations.bottomSheetLabel),
backgroundColor: backgroundColor,
......
......@@ -1789,7 +1789,7 @@ void main() {
});
group('constraints', () {
testWidgets('default constraints are max width 640 in material 3', (WidgetTester tester) async {
testWidgets('default constraints are max width 640 in material 3', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.light(useMaterial3: true),
......@@ -2045,6 +2045,58 @@ void main() {
);
});
group('scrollControlDisabledMaxHeightRatio', () {
Future<void> test(
WidgetTester tester,
bool isScrollControlled,
double scrollControlDisabledMaxHeightRatio,
) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Builder(builder: (BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('Press me'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
isScrollControlled: isScrollControlled,
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
builder: (BuildContext context) => const SizedBox.expand(
child: Text('BottomSheet'),
),
);
},
),
);
}),
),
),
);
await tester.tap(find.text('Press me'));
await tester.pumpAndSettle();
expect(
tester.getRect(find.text('BottomSheet')),
Rect.fromLTRB(
80,
600 * (isScrollControlled ? 0 : (1 - scrollControlDisabledMaxHeightRatio)),
720,
600,
),
);
}
testWidgets('works at 9 / 16', (WidgetTester tester) {
return test(tester, false, 9.0 / 16.0);
});
testWidgets('works at 8 / 16', (WidgetTester tester) {
return test(tester, false, 8.0 / 16.0);
});
testWidgets('works at isScrollControlled', (WidgetTester tester) {
return test(tester, true, 8.0 / 16.0);
});
});
});
group('showModalBottomSheet modalBarrierDismissLabel', () {
......
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