🚀 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.
This commit is contained in:
parent
300c5d8285
commit
9f374f12ea
@ -26,6 +26,7 @@ const Duration _bottomSheetExitDuration = Duration(milliseconds: 200);
|
|||||||
const Curve _modalBottomSheetCurve = decelerateEasing;
|
const Curve _modalBottomSheetCurve = decelerateEasing;
|
||||||
const double _minFlingVelocity = 700.0;
|
const double _minFlingVelocity = 700.0;
|
||||||
const double _closeProgressThreshold = 0.5;
|
const double _closeProgressThreshold = 0.5;
|
||||||
|
const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0;
|
||||||
|
|
||||||
/// A callback for when the user begins dragging the bottom sheet.
|
/// A callback for when the user begins dragging the bottom sheet.
|
||||||
///
|
///
|
||||||
@ -471,24 +472,26 @@ class _DragHandle extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget {
|
class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget {
|
||||||
|
|
||||||
const _BottomSheetLayoutWithSizeListener({
|
const _BottomSheetLayoutWithSizeListener({
|
||||||
|
required this.onChildSizeChanged,
|
||||||
required this.animationValue,
|
required this.animationValue,
|
||||||
required this.isScrollControlled,
|
required this.isScrollControlled,
|
||||||
required this.onChildSizeChanged,
|
required this.scrollControlDisabledMaxHeightRatio,
|
||||||
super.child,
|
super.child,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final _SizeChangeCallback<Size> onChildSizeChanged;
|
||||||
final double animationValue;
|
final double animationValue;
|
||||||
final bool isScrollControlled;
|
final bool isScrollControlled;
|
||||||
final _SizeChangeCallback<Size> onChildSizeChanged;
|
final double scrollControlDisabledMaxHeightRatio;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_RenderBottomSheetLayoutWithSizeListener createRenderObject(BuildContext context) {
|
_RenderBottomSheetLayoutWithSizeListener createRenderObject(BuildContext context) {
|
||||||
return _RenderBottomSheetLayoutWithSizeListener(
|
return _RenderBottomSheetLayoutWithSizeListener(
|
||||||
|
onChildSizeChanged: onChildSizeChanged,
|
||||||
animationValue: animationValue,
|
animationValue: animationValue,
|
||||||
isScrollControlled: isScrollControlled,
|
isScrollControlled: isScrollControlled,
|
||||||
onChildSizeChanged: onChildSizeChanged,
|
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,6 +500,7 @@ class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget {
|
|||||||
renderObject.onChildSizeChanged = onChildSizeChanged;
|
renderObject.onChildSizeChanged = onChildSizeChanged;
|
||||||
renderObject.animationValue = animationValue;
|
renderObject.animationValue = animationValue;
|
||||||
renderObject.isScrollControlled = isScrollControlled;
|
renderObject.isScrollControlled = isScrollControlled;
|
||||||
|
renderObject.scrollControlDisabledMaxHeightRatio = scrollControlDisabledMaxHeightRatio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,9 +510,11 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox {
|
|||||||
required _SizeChangeCallback<Size> onChildSizeChanged,
|
required _SizeChangeCallback<Size> onChildSizeChanged,
|
||||||
required double animationValue,
|
required double animationValue,
|
||||||
required bool isScrollControlled,
|
required bool isScrollControlled,
|
||||||
}) : _animationValue = animationValue,
|
required double scrollControlDisabledMaxHeightRatio,
|
||||||
|
}) : _onChildSizeChanged = onChildSizeChanged,
|
||||||
|
_animationValue = animationValue,
|
||||||
_isScrollControlled = isScrollControlled,
|
_isScrollControlled = isScrollControlled,
|
||||||
_onChildSizeChanged = onChildSizeChanged,
|
_scrollControlDisabledMaxHeightRatio = scrollControlDisabledMaxHeightRatio,
|
||||||
super(child);
|
super(child);
|
||||||
|
|
||||||
Size _lastSize = Size.zero;
|
Size _lastSize = Size.zero;
|
||||||
@ -546,6 +552,17 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox {
|
|||||||
markNeedsLayout();
|
markNeedsLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double get scrollControlDisabledMaxHeightRatio => _scrollControlDisabledMaxHeightRatio;
|
||||||
|
double _scrollControlDisabledMaxHeightRatio;
|
||||||
|
set scrollControlDisabledMaxHeightRatio(double newValue) {
|
||||||
|
if (_scrollControlDisabledMaxHeightRatio == newValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_scrollControlDisabledMaxHeightRatio = newValue;
|
||||||
|
markNeedsLayout();
|
||||||
|
}
|
||||||
|
|
||||||
Size _getSize(BoxConstraints constraints) {
|
Size _getSize(BoxConstraints constraints) {
|
||||||
return constraints.constrain(constraints.biggest);
|
return constraints.constrain(constraints.biggest);
|
||||||
}
|
}
|
||||||
@ -591,13 +608,13 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox {
|
|||||||
return _getSize(constraints);
|
return _getSize(constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxConstraints _getConstraintsForChild(BoxConstraints constraints) {
|
BoxConstraints _getConstraintsForChild(BoxConstraints constraints) {
|
||||||
return BoxConstraints(
|
return BoxConstraints(
|
||||||
minWidth: constraints.maxWidth,
|
minWidth: constraints.maxWidth,
|
||||||
maxWidth: constraints.maxWidth,
|
maxWidth: constraints.maxWidth,
|
||||||
maxHeight: isScrollControlled
|
maxHeight: isScrollControlled
|
||||||
? constraints.maxHeight
|
? constraints.maxHeight
|
||||||
: constraints.maxHeight * 9.0 / 16.0,
|
: constraints.maxHeight * scrollControlDisabledMaxHeightRatio,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,12 +651,14 @@ class _ModalBottomSheet<T> extends StatefulWidget {
|
|||||||
this.clipBehavior,
|
this.clipBehavior,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
this.isScrollControlled = false,
|
this.isScrollControlled = false,
|
||||||
|
this.scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio,
|
||||||
this.enableDrag = true,
|
this.enableDrag = true,
|
||||||
this.showDragHandle = false,
|
this.showDragHandle = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ModalBottomSheetRoute<T> route;
|
final ModalBottomSheetRoute<T> route;
|
||||||
final bool isScrollControlled;
|
final bool isScrollControlled;
|
||||||
|
final double scrollControlDisabledMaxHeightRatio;
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
final double? elevation;
|
final double? elevation;
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder? shape;
|
||||||
@ -730,6 +749,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
|||||||
},
|
},
|
||||||
animationValue: animationValue,
|
animationValue: animationValue,
|
||||||
isScrollControlled: widget.isScrollControlled,
|
isScrollControlled: widget.isScrollControlled,
|
||||||
|
scrollControlDisabledMaxHeightRatio: widget.scrollControlDisabledMaxHeightRatio,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -815,6 +835,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
|||||||
this.enableDrag = true,
|
this.enableDrag = true,
|
||||||
this.showDragHandle,
|
this.showDragHandle,
|
||||||
required this.isScrollControlled,
|
required this.isScrollControlled,
|
||||||
|
this.scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio,
|
||||||
super.settings,
|
super.settings,
|
||||||
this.transitionAnimationController,
|
this.transitionAnimationController,
|
||||||
this.anchorPoint,
|
this.anchorPoint,
|
||||||
@ -842,6 +863,13 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
|||||||
/// to have the bottom sheet be draggable.
|
/// to have the bottom sheet be draggable.
|
||||||
final bool isScrollControlled;
|
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.
|
/// The bottom sheet's background color.
|
||||||
///
|
///
|
||||||
/// Defines the bottom sheet's [Material.color].
|
/// Defines the bottom sheet's [Material.color].
|
||||||
@ -1026,6 +1054,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
|||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
constraints: constraints,
|
constraints: constraints,
|
||||||
isScrollControlled: isScrollControlled,
|
isScrollControlled: isScrollControlled,
|
||||||
|
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
|
||||||
enableDrag: enableDrag,
|
enableDrag: enableDrag,
|
||||||
showDragHandle: showDragHandle ?? (enableDrag && (sheetTheme.showDragHandle ?? false)),
|
showDragHandle: showDragHandle ?? (enableDrag && (sheetTheme.showDragHandle ?? false)),
|
||||||
);
|
);
|
||||||
@ -1192,6 +1221,7 @@ Future<T?> showModalBottomSheet<T>({
|
|||||||
BoxConstraints? constraints,
|
BoxConstraints? constraints,
|
||||||
Color? barrierColor,
|
Color? barrierColor,
|
||||||
bool isScrollControlled = false,
|
bool isScrollControlled = false,
|
||||||
|
double scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio,
|
||||||
bool useRootNavigator = false,
|
bool useRootNavigator = false,
|
||||||
bool isDismissible = true,
|
bool isDismissible = true,
|
||||||
bool enableDrag = true,
|
bool enableDrag = true,
|
||||||
@ -1210,6 +1240,7 @@ Future<T?> showModalBottomSheet<T>({
|
|||||||
builder: builder,
|
builder: builder,
|
||||||
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
|
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
|
||||||
isScrollControlled: isScrollControlled,
|
isScrollControlled: isScrollControlled,
|
||||||
|
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
|
||||||
barrierLabel: barrierLabel ?? localizations.scrimLabel,
|
barrierLabel: barrierLabel ?? localizations.scrimLabel,
|
||||||
barrierOnTapHint: localizations.scrimOnTapHint(localizations.bottomSheetLabel),
|
barrierOnTapHint: localizations.scrimOnTapHint(localizations.bottomSheetLabel),
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
|
@ -1789,7 +1789,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('constraints', () {
|
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(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: ThemeData.light(useMaterial3: true),
|
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', () {
|
group('showModalBottomSheet modalBarrierDismissLabel', () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user