@@ -663,14 +663,14 @@ class _SlidingTapGestureRecognizer extends VerticalDragGestureRecognizer {
663663// enters, leaves, or ends this `MetaData` widget, corresponding methods of this
664664// class will be called.
665665//
666- // Multiple `_ActionSheetSlideTarget `s might be nested.
666+ // Multiple `_SlideTarget `s might be nested.
667667// `_TargetSelectionGestureRecognizer` uses a simple algorithm that only
668668// compares if the inner-most slide target has changed (which suffices our use
669669// case). Semantically, this means that all outer targets will be treated as
670670// identical to the inner-most one, i.e. when the pointer enters or leaves a
671671// slide target, the corresponding method will be called on all targets that
672672// nest it.
673- abstract class _ActionSheetSlideTarget {
673+ abstract class _SlideTarget {
674674 // A pointer has entered this region.
675675 //
676676 // This includes:
@@ -702,7 +702,7 @@ abstract class _ActionSheetSlideTarget {
702702}
703703
704704// Recognizes sliding taps and thereupon interacts with
705- // `_ActionSheetSlideTarget `s.
705+ // `_SlideTarget `s.
706706class _TargetSelectionGestureRecognizer extends GestureRecognizer {
707707 _TargetSelectionGestureRecognizer ({super .debugOwner, required this .hitTest})
708708 : _slidingTap = _SlidingTapGestureRecognizer (debugOwner: debugOwner) {
@@ -715,7 +715,7 @@ class _TargetSelectionGestureRecognizer extends GestureRecognizer {
715715
716716 final _HitTester hitTest;
717717
718- final List <_ActionSheetSlideTarget > _currentTargets = < _ActionSheetSlideTarget > [];
718+ final List <_SlideTarget > _currentTargets = < _SlideTarget > [];
719719 final _SlidingTapGestureRecognizer _slidingTap;
720720
721721 @override
@@ -744,7 +744,7 @@ class _TargetSelectionGestureRecognizer extends GestureRecognizer {
744744 super .dispose ();
745745 }
746746
747- // Collect the `_ActionSheetSlideTarget `s that are currently hit by the
747+ // Collect the `_SlideTarget `s that are currently hit by the
748748 // pointer, check whether the current target have changed, and invoke their
749749 // methods if necessary.
750750 //
@@ -755,27 +755,27 @@ class _TargetSelectionGestureRecognizer extends GestureRecognizer {
755755
756756 // A slide target might nest other targets, therefore multiple targets might
757757 // be found.
758- final List <_ActionSheetSlideTarget > foundTargets = < _ActionSheetSlideTarget > [];
758+ final List <_SlideTarget > foundTargets = < _SlideTarget > [];
759759 for (final HitTestEntry entry in result.path) {
760760 if (entry.target case final RenderMetaData target) {
761- if (target.metaData is _ActionSheetSlideTarget ) {
762- foundTargets.add (target.metaData as _ActionSheetSlideTarget );
761+ if (target.metaData is _SlideTarget ) {
762+ foundTargets.add (target.metaData as _SlideTarget );
763763 }
764764 }
765765 }
766766
767767 // Compare whether the active target has changed by simply comparing the
768768 // first (inner-most) avatar of the nest, ignoring the cases where
769- // _currentTargets intersect with foundTargets (see _ActionSheetSlideTarget 's
769+ // _currentTargets intersect with foundTargets (see _SlideTarget 's
770770 // document for more explanation).
771771 if (_currentTargets.firstOrNull != foundTargets.firstOrNull) {
772- for (final _ActionSheetSlideTarget target in _currentTargets) {
772+ for (final _SlideTarget target in _currentTargets) {
773773 target.didLeave ();
774774 }
775775 _currentTargets
776776 ..clear ()
777777 ..addAll (foundTargets);
778- for (final _ActionSheetSlideTarget target in _currentTargets) {
778+ for (final _SlideTarget target in _currentTargets) {
779779 target.didEnter (fromPointerDown: fromPointerDown);
780780 }
781781 }
@@ -791,14 +791,14 @@ class _TargetSelectionGestureRecognizer extends GestureRecognizer {
791791
792792 void _onEnd (Offset globalPosition) {
793793 _updateDrag (globalPosition, fromPointerDown: false );
794- for (final _ActionSheetSlideTarget target in _currentTargets) {
794+ for (final _SlideTarget target in _currentTargets) {
795795 target.didConfirm ();
796796 }
797797 _currentTargets.clear ();
798798 }
799799
800800 void _onCancel () {
801- for (final _ActionSheetSlideTarget target in _currentTargets) {
801+ for (final _SlideTarget target in _currentTargets) {
802802 target.didLeave ();
803803 }
804804 _currentTargets.clear ();
@@ -949,6 +949,9 @@ class CupertinoActionSheet extends StatefulWidget {
949949}
950950
951951class _CupertinoActionSheetState extends State <CupertinoActionSheet > {
952+ int ? _pressedIndex;
953+ static const int _kCancelButtonIndex = - 1 ;
954+
952955 ScrollController ? _backupMessageScrollController;
953956
954957 ScrollController ? _backupActionScrollController;
@@ -1004,6 +1007,20 @@ class _CupertinoActionSheetState extends State<CupertinoActionSheet> {
10041007 );
10051008 }
10061009
1010+ void _onPressedUpdate (int actionIndex, bool state) {
1011+ if (! state) {
1012+ if (_pressedIndex == actionIndex) {
1013+ setState (() {
1014+ _pressedIndex = null ;
1015+ });
1016+ }
1017+ } else {
1018+ setState (() {
1019+ _pressedIndex = actionIndex;
1020+ });
1021+ }
1022+ }
1023+
10071024 Widget _buildCancelButton () {
10081025 assert (widget.cancelButton != null );
10091026 final double cancelPadding = (widget.actions != null || widget.message != null || widget.title != null )
@@ -1012,7 +1029,10 @@ class _CupertinoActionSheetState extends State<CupertinoActionSheet> {
10121029 padding: EdgeInsets .only (top: cancelPadding),
10131030 child: _ActionSheetButtonBackground (
10141031 isCancel: true ,
1015- onPressStateChange: (_) {},
1032+ pressed: _pressedIndex == _kCancelButtonIndex,
1033+ onPressStateChange: (bool state) {
1034+ _onPressedUpdate (_kCancelButtonIndex, state);
1035+ },
10161036 child: widget.cancelButton! ,
10171037 ),
10181038 );
@@ -1106,6 +1126,8 @@ class _CupertinoActionSheetState extends State<CupertinoActionSheet> {
11061126 child: BackdropFilter (
11071127 filter: ImageFilter .blur (sigmaX: _kBlurAmount, sigmaY: _kBlurAmount),
11081128 child: _ActionSheetMainSheet (
1129+ pressedIndex: _pressedIndex,
1130+ onPressedUpdate: _onPressedUpdate,
11091131 scrollController: _effectiveActionScrollController,
11101132 contentSection: _buildContent (context),
11111133 actions: widget.actions ?? List <Widget >.empty (),
@@ -1208,16 +1230,16 @@ class CupertinoActionSheetAction extends StatefulWidget {
12081230}
12091231
12101232class _CupertinoActionSheetActionState extends State <CupertinoActionSheetAction >
1211- implements _ActionSheetSlideTarget {
1212- // |_ActionSheetSlideTarget |
1233+ implements _SlideTarget {
1234+ // |_SlideTarget |
12131235 @override
12141236 void didEnter ({required bool fromPointerDown}) {}
12151237
1216- // |_ActionSheetSlideTarget |
1238+ // |_SlideTarget |
12171239 @override
12181240 void didLeave () {}
12191241
1220- // |_ActionSheetSlideTarget |
1242+ // |_SlideTarget |
12211243 @override
12221244 void didConfirm () {
12231245 widget.onPressed ();
@@ -1307,15 +1329,23 @@ class _CupertinoActionSheetActionState extends State<CupertinoActionSheetAction>
13071329
13081330// Renders the background of a button (both the pressed background and the idle
13091331// background) and reports its state to the parent with `onPressStateChange`.
1332+ //
1333+ // Although this class doesn't keep any states, it's still a stateful widget
1334+ // because the state is used as a persistent object across rebuilds to provide
1335+ // to [MetaData.data].
13101336class _ActionSheetButtonBackground extends StatefulWidget {
13111337 const _ActionSheetButtonBackground ({
13121338 this .isCancel = false ,
1339+ required this .pressed,
13131340 this .onPressStateChange,
13141341 required this .child,
13151342 });
13161343
13171344 final bool isCancel;
13181345
1346+ /// Whether the user is holding on this button.
1347+ final bool pressed;
1348+
13191349 /// Called when the user taps down or lifts up on the button.
13201350 ///
13211351 /// The boolean value is true if the user is tapping down on the button.
@@ -1330,9 +1360,7 @@ class _ActionSheetButtonBackground extends StatefulWidget {
13301360 _ActionSheetButtonBackgroundState createState () => _ActionSheetButtonBackgroundState ();
13311361}
13321362
1333- class _ActionSheetButtonBackgroundState extends State <_ActionSheetButtonBackground > implements _ActionSheetSlideTarget {
1334- bool isBeingPressed = false ;
1335-
1363+ class _ActionSheetButtonBackgroundState extends State <_ActionSheetButtonBackground > implements _SlideTarget {
13361364 void _emitVibration (){
13371365 switch (defaultTargetPlatform) {
13381366 case TargetPlatform .iOS:
@@ -1346,27 +1374,24 @@ class _ActionSheetButtonBackgroundState extends State<_ActionSheetButtonBackgrou
13461374 }
13471375 }
13481376
1349- // |_ActionSheetSlideTarget |
1377+ // |_SlideTarget |
13501378 @override
13511379 void didEnter ({required bool fromPointerDown}) {
1352- setState (() { isBeingPressed = true ; });
13531380 widget.onPressStateChange? .call (true );
13541381 if (! fromPointerDown) {
13551382 _emitVibration ();
13561383 }
13571384 }
13581385
1359- // |_ActionSheetSlideTarget |
1386+ // |_SlideTarget |
13601387 @override
13611388 void didLeave () {
1362- setState (() { isBeingPressed = false ; });
13631389 widget.onPressStateChange? .call (false );
13641390 }
13651391
1366- // |_ActionSheetSlideTarget |
1392+ // |_SlideTarget |
13671393 @override
13681394 void didConfirm () {
1369- setState (() { isBeingPressed = false ; });
13701395 widget.onPressStateChange? .call (false );
13711396 }
13721397
@@ -1375,11 +1400,11 @@ class _ActionSheetButtonBackgroundState extends State<_ActionSheetButtonBackgrou
13751400 late final Color backgroundColor;
13761401 BorderRadius ? borderRadius;
13771402 if (! widget.isCancel) {
1378- backgroundColor = isBeingPressed
1403+ backgroundColor = widget.pressed
13791404 ? _kActionSheetPressedColor
13801405 : _kActionSheetBackgroundColor;
13811406 } else {
1382- backgroundColor = isBeingPressed
1407+ backgroundColor = widget.pressed
13831408 ? _kActionSheetCancelPressedColor
13841409 : _kActionSheetCancelColor;
13851410 borderRadius = const BorderRadius .all (Radius .circular (_kCornerRadius));
@@ -1566,6 +1591,7 @@ class _ActionSheetActionSection extends StatelessWidget {
15661591 ));
15671592 }
15681593 column.add (_ActionSheetButtonBackground (
1594+ pressed: pressedIndex == actionIndex,
15691595 onPressStateChange: (bool state) {
15701596 onPressedUpdate (actionIndex, state);
15711597 },
@@ -1586,86 +1612,69 @@ class _ActionSheetActionSection extends StatelessWidget {
15861612}
15871613
15881614// The part of an action sheet without the cancel button.
1589- class _ActionSheetMainSheet extends StatefulWidget {
1615+ class _ActionSheetMainSheet extends StatelessWidget {
15901616 const _ActionSheetMainSheet ({
1617+ required this .pressedIndex,
1618+ required this .onPressedUpdate,
15911619 required this .scrollController,
15921620 required this .actions,
15931621 required this .contentSection,
15941622 required this .dividerColor,
15951623 });
15961624
1625+ final int ? pressedIndex;
1626+ final _PressedUpdateHandler onPressedUpdate;
15971627 final ScrollController ? scrollController;
15981628 final List <Widget > actions;
15991629 final Widget ? contentSection;
16001630 final Color dividerColor;
16011631
1602- @override
1603- _ActionSheetMainSheetState createState () => _ActionSheetMainSheetState ();
1604- }
1605-
1606- class _ActionSheetMainSheetState extends State <_ActionSheetMainSheet > {
1607- int ? _pressedIndex;
1608-
1609- bool get _hasContent => widget.contentSection != null ;
1610- bool get _hasActions => widget.actions.isNotEmpty;
1611-
1612- void _onPressedUpdate (int actionIndex, bool state) {
1613- if (! state) {
1614- if (_pressedIndex == actionIndex) {
1615- setState (() {
1616- _pressedIndex = null ;
1617- });
1618- }
1619- } else {
1620- setState (() {
1621- _pressedIndex = actionIndex;
1622- });
1623- }
1632+ Widget _scrolledActionsSection (BuildContext context) {
1633+ final Color backgroundColor = CupertinoDynamicColor .resolve (_kActionSheetBackgroundColor, context);
1634+ return _OverscrollBackground (
1635+ scrollController: scrollController,
1636+ color: backgroundColor,
1637+ child: _ActionSheetActionSection (
1638+ actions: actions,
1639+ scrollController: scrollController,
1640+ dividerColor: dividerColor,
1641+ backgroundColor: backgroundColor,
1642+ pressedIndex: pressedIndex,
1643+ onPressedUpdate: onPressedUpdate,
1644+ ),
1645+ );
16241646 }
16251647
16261648 Widget _dividerAndActionsSection (BuildContext context) {
1627- if (! _hasActions) {
1628- return _empty;
1629- }
16301649 final Color backgroundColor = CupertinoDynamicColor .resolve (_kActionSheetBackgroundColor, context);
16311650 return Column (
16321651 mainAxisSize: MainAxisSize .min,
16331652 crossAxisAlignment: CrossAxisAlignment .stretch,
16341653 children: < Widget > [
1635- if (_hasContent)
1636- _Divider (
1637- dividerColor: widget.dividerColor,
1638- hiddenColor: backgroundColor,
1639- hidden: false ,
1640- ),
1654+ _Divider (
1655+ dividerColor: dividerColor,
1656+ hiddenColor: backgroundColor,
1657+ hidden: false ,
1658+ ),
16411659 Flexible (
1642- child: _OverscrollBackground (
1643- scrollController: widget.scrollController,
1644- color: backgroundColor,
1645- child: _ActionSheetActionSection (
1646- actions: widget.actions,
1647- scrollController: widget.scrollController,
1648- pressedIndex: _pressedIndex,
1649- dividerColor: widget.dividerColor,
1650- backgroundColor: backgroundColor,
1651- onPressedUpdate: _onPressedUpdate,
1652- ),
1653- ),
1660+ child: _scrolledActionsSection (context),
16541661 ),
16551662 ],
16561663 );
16571664 }
16581665
16591666 @override
16601667 Widget build (BuildContext context) {
1661- return LayoutBuilder (
1662- builder: (BuildContext context, BoxConstraints constraints) {
1663- return _PriorityColumn (
1664- top: widget.contentSection ?? _empty,
1665- bottom: _dividerAndActionsSection (context),
1666- bottomMinHeight: _kActionSheetActionsSectionMinHeight + _kDividerThickness,
1667- );
1668- },
1668+ if (actions.isEmpty) {
1669+ return contentSection ?? _empty;
1670+ }
1671+ if (contentSection == null ) {
1672+ return _scrolledActionsSection (context);
1673+ }
1674+ return _PriorityColumn (
1675+ top: contentSection! ,
1676+ bottom: _dividerAndActionsSection (context),
1677+ bottomMinHeight: _kActionSheetActionsSectionMinHeight + _kDividerThickness,
16691678 );
16701679 }
16711680
0 commit comments