From 0896292e35e5963788974f4a8857be826e025b73 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 26 Nov 2024 06:54:53 +0800 Subject: [PATCH] Refactor bottom sheet & related widgets (#159257) This PR refactors Material's bottom sheet & related widgets. It also replaces internal usage of deprecated types such as `MaterialState` with `WidgetState`. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/material/bottom_sheet.dart | 93 ++++++------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index 9dfeec84cf..735551f992 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -15,17 +15,16 @@ import 'bottom_sheet_theme.dart'; import 'color_scheme.dart'; import 'colors.dart'; import 'constants.dart'; -import 'curves.dart'; import 'debug.dart'; import 'material.dart'; import 'material_localizations.dart'; -import 'material_state.dart'; +import 'motion.dart'; import 'scaffold.dart'; import 'theme.dart'; const Duration _bottomSheetEnterDuration = Duration(milliseconds: 250); const Duration _bottomSheetExitDuration = Duration(milliseconds: 200); -const Curve _modalBottomSheetCurve = decelerateEasing; +const Curve _modalBottomSheetCurve = Easing.legacyDecelerate; const double _minFlingVelocity = 700.0; const double _closeProgressThreshold = 0.5; const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0; @@ -266,11 +265,11 @@ class _BottomSheetState extends State { bool get _dismissUnderway => widget.animationController!.status == AnimationStatus.reverse; - Set dragHandleMaterialState = {}; + Set dragHandleStates = {}; void _handleDragStart(DragStartDetails details) { setState(() { - dragHandleMaterialState.add(MaterialState.dragged); + dragHandleStates.add(WidgetState.dragged); }); widget.onDragStart?.call(details); } @@ -297,7 +296,7 @@ class _BottomSheetState extends State { return; } setState(() { - dragHandleMaterialState.remove(MaterialState.dragged); + dragHandleStates.remove(WidgetState.dragged); }); bool isClosing = false; if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) { @@ -335,12 +334,12 @@ class _BottomSheetState extends State { } void _handleDragHandleHover(bool hovering) { - if (hovering != dragHandleMaterialState.contains(MaterialState.hovered)) { + if (hovering != dragHandleStates.contains(WidgetState.hovered)) { setState(() { if (hovering){ - dragHandleMaterialState.add(MaterialState.hovered); + dragHandleStates.add(WidgetState.hovered); } else { - dragHandleMaterialState.remove(MaterialState.hovered); + dragHandleStates.remove(WidgetState.hovered); } }); } @@ -361,11 +360,11 @@ class _BottomSheetState extends State { final bool showDragHandle = widget.showDragHandle ?? (widget.enableDrag && (bottomSheetTheme.showDragHandle ?? false)); Widget? dragHandle; - if (showDragHandle){ + if (showDragHandle) { dragHandle = _DragHandle( onSemanticsTap: widget.onClosing, handleHover: _handleDragHandleHover, - materialState: dragHandleMaterialState, + states: dragHandleStates, dragHandleColor: widget.dragHandleColor, dragHandleSize: widget.dragHandleSize, ); @@ -431,20 +430,18 @@ class _BottomSheetState extends State { // See scaffold.dart -typedef _SizeChangeCallback = void Function(Size size); - class _DragHandle extends StatelessWidget { const _DragHandle({ required this.onSemanticsTap, required this.handleHover, - required this.materialState, + required this.states, this.dragHandleColor, this.dragHandleSize, }); final VoidCallback? onSemanticsTap; final ValueChanged handleHover; - final Set materialState; + final Set states; final Color? dragHandleColor; final Size? dragHandleSize; @@ -470,8 +467,8 @@ class _DragHandle extends StatelessWidget { width: handleSize.width, decoration: BoxDecoration( borderRadius: BorderRadius.circular(handleSize.height/2), - color: MaterialStateProperty.resolveAs(dragHandleColor, materialState) - ?? MaterialStateProperty.resolveAs(bottomSheetTheme.dragHandleColor, materialState) + color: WidgetStateProperty.resolveAs(dragHandleColor, states) + ?? WidgetStateProperty.resolveAs(bottomSheetTheme.dragHandleColor, states) ?? m3Defaults.dragHandleColor, ), ), @@ -491,7 +488,7 @@ class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget { super.child, }); - final _SizeChangeCallback onChildSizeChanged; + final ValueChanged onChildSizeChanged; final double animationValue; final bool isScrollControlled; final double scrollControlDisabledMaxHeightRatio; @@ -518,7 +515,7 @@ class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget { class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { _RenderBottomSheetLayoutWithSizeListener({ RenderBox? child, - required _SizeChangeCallback onChildSizeChanged, + required ValueChanged onChildSizeChanged, required double animationValue, required bool isScrollControlled, required double scrollControlDisabledMaxHeightRatio, @@ -530,9 +527,9 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { Size _lastSize = Size.zero; - _SizeChangeCallback get onChildSizeChanged => _onChildSizeChanged; - _SizeChangeCallback _onChildSizeChanged; - set onChildSizeChanged(_SizeChangeCallback newCallback) { + ValueChanged get onChildSizeChanged => _onChildSizeChanged; + ValueChanged _onChildSizeChanged; + set onChildSizeChanged(ValueChanged newCallback) { if (_onChildSizeChanged == newCallback) { return; } @@ -574,50 +571,20 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { markNeedsLayout(); } - Size _getSize(BoxConstraints constraints) { - return constraints.constrain(constraints.biggest); - } + @override + double computeMinIntrinsicWidth(double height) => 0.0; @override - double computeMinIntrinsicWidth(double height) { - final double width = _getSize(BoxConstraints.tightForFinite(height: height)).width; - if (width.isFinite) { - return width; - } - return 0.0; - } + double computeMaxIntrinsicWidth(double height) => 0.0; @override - double computeMaxIntrinsicWidth(double height) { - final double width = _getSize(BoxConstraints.tightForFinite(height: height)).width; - if (width.isFinite) { - return width; - } - return 0.0; - } + double computeMinIntrinsicHeight(double width) => 0.0; @override - double computeMinIntrinsicHeight(double width) { - final double height = _getSize(BoxConstraints.tightForFinite(width: width)).height; - if (height.isFinite) { - return height; - } - return 0.0; - } + double computeMaxIntrinsicHeight(double width) => 0.0; @override - double computeMaxIntrinsicHeight(double width) { - final double height = _getSize(BoxConstraints.tightForFinite(width: width)).height; - if (height.isFinite) { - return height; - } - return 0.0; - } - - @override - Size computeDryLayout(BoxConstraints constraints) { - return _getSize(constraints); - } + Size computeDryLayout(BoxConstraints constraints) => constraints.biggest; @override double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) { @@ -631,7 +598,7 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { return null; } final Size childSize = childConstraints.isTight ? childConstraints.smallest : child.getDryLayout(childConstraints); - return result + _getPositionForChild(_getSize(constraints), childSize).dy; + return result + _getPositionForChild(constraints.biggest, childSize).dy; } BoxConstraints _getConstraintsForChild(BoxConstraints constraints) { @@ -650,7 +617,7 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { @override void performLayout() { - size = _getSize(constraints); + size = constraints.biggest; final RenderBox? child = this.child; if (child == null) { return; @@ -1137,11 +1104,11 @@ class ModalBottomSheetRoute extends PopupRoute { @override Widget buildModalBarrier() { - if (barrierColor.alpha != 0 && !offstage) { // changedInternalState is called if barrierColor or offstage updates - assert(barrierColor != barrierColor.withOpacity(0.0)); + if (barrierColor.a != 0 && !offstage) { // changedInternalState is called if barrierColor or offstage updates + assert(barrierColor != barrierColor.withValues(alpha: 0.0)); final Animation color = animation!.drive( ColorTween( - begin: barrierColor.withOpacity(0.0), + begin: barrierColor.withValues(alpha: 0.0), end: barrierColor, // changedInternalState is called if barrierColor updates ).chain(CurveTween(curve: barrierCurve)), // changedInternalState is called if barrierCurve updates );