@@ -107,7 +107,7 @@ class SlidableDelegateContext {
107107 const SlidableDelegateContext (
108108 this .slidable,
109109 this .showActions,
110- this .dragExtent ,
110+ this .dragSign ,
111111 this .controller,
112112 );
113113
@@ -126,7 +126,7 @@ class SlidableDelegateContext {
126126 /// Whether the actions have to be shown.
127127 final bool showActions;
128128
129- final double dragExtent ;
129+ final double dragSign ;
130130
131131 /// The animation controller which value depends on `dragExtent` .
132132 final AnimationController controller;
@@ -199,10 +199,10 @@ abstract class SlidableStackDelegate extends SlidableDelegate {
199199 Widget buildActions (BuildContext context, SlidableDelegateContext ctx) {
200200 final animation = new Tween (
201201 begin: Offset .zero,
202- end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragExtent.sign ),
202+ end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragSign ),
203203 ).animate (ctx.controller);
204204
205- if (ctx.controller.value != .0 && ctx.dragExtent != . 0 ) {
205+ if (ctx.controller.value != .0 ) {
206206 return new Container (
207207 child: new Stack (
208208 children: < Widget > [
@@ -237,7 +237,7 @@ class SlidableStrechDelegate extends SlidableStackDelegate {
237237 Widget buildStackActions (BuildContext context, SlidableDelegateContext ctx) {
238238 final animation = new Tween (
239239 begin: Offset .zero,
240- end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragExtent.sign ),
240+ end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragSign ),
241241 ).animate (ctx.controller);
242242
243243 return new Positioned .fill (
@@ -395,12 +395,12 @@ class SlidableDrawerDelegate extends SlidableStackDelegate {
395395///
396396/// By sliding in one of these direction, slide actions will appear.
397397class Slidable extends StatefulWidget {
398- /// Creates a widget that can be dismissed .
398+ /// Creates a widget that can be slid .
399399 ///
400400 /// The [actions] contains the slide actions that appears when the child has been dragged down or to the right.
401401 /// The [secondaryActions] contains the slide actions that appears when the child has been dragged up or to the left.
402402 ///
403- /// The [delegate] argument must not be null. The [actionExtentRatio]
403+ /// The [delegate] and [closeOnScroll] arguments must not be null. The [actionExtentRatio]
404404 /// and [showAllActionsThreshold] arguments must be greater or equal than 0 and less or equal than 1.
405405 Slidable ({
406406 Key key,
@@ -412,6 +412,7 @@ class Slidable extends StatefulWidget {
412412 double actionExtentRatio = _kActionsExtentRatio,
413413 Duration movementDuration = const Duration (milliseconds: 200 ),
414414 Axis direction = Axis .horizontal,
415+ bool closeOnScroll = true ,
415416 }) : this .builder (
416417 key: key,
417418 child: child,
@@ -423,8 +424,16 @@ class Slidable extends StatefulWidget {
423424 actionExtentRatio: actionExtentRatio,
424425 movementDuration: movementDuration,
425426 direction: direction,
427+ closeOnScroll: closeOnScroll,
426428 );
427429
430+ /// Creates a widget that can be slid.
431+ ///
432+ /// The [actionDelegate] is a delegate that builds the slide actions that appears when the child has been dragged down or to the right.
433+ /// The [secondaryActionDelegate] is a delegate that builds the slide actions that appears when the child has been dragged up or to the left.
434+ ///
435+ /// The [delegate] and [closeOnScroll] arguments must not be null. The [actionExtentRatio]
436+ /// and [showAllActionsThreshold] arguments must be greater or equal than 0 and less or equal than 1.
428437 Slidable .builder ({
429438 Key key,
430439 @required this .child,
@@ -435,6 +444,7 @@ class Slidable extends StatefulWidget {
435444 this .actionExtentRatio = _kActionsExtentRatio,
436445 this .movementDuration = const Duration (milliseconds: 200 ),
437446 this .direction = Axis .horizontal,
447+ this .closeOnScroll = true ,
438448 }) : assert (delegate != null ),
439449 assert (direction != null ),
440450 assert (
@@ -447,6 +457,7 @@ class Slidable extends StatefulWidget {
447457 actionExtentRatio >= .0 &&
448458 actionExtentRatio <= 1.0 ,
449459 'actionExtentRatio must be between 0.0 and 1.0' ),
460+ assert (closeOnScroll != null ),
450461 super (key: key);
451462
452463 /// The widget below this widget in the tree.
@@ -479,6 +490,16 @@ class Slidable extends StatefulWidget {
479490 /// Defines the duration for card to go to final position or to come back to original position if threshold not reached.
480491 final Duration movementDuration;
481492
493+ /// Specifies to close this slidable after the closest [Scrollable] 's position changed.
494+ ///
495+ /// Defaults to true.
496+ final bool closeOnScroll;
497+
498+ /// The state from the closest instance of this class that encloses the given context.
499+ static SlidableState of (BuildContext context) {
500+ return context.ancestorStateOfType (const TypeMatcher <SlidableState >());
501+ }
502+
482503 @override
483504 SlidableState createState () => SlidableState ();
484505}
@@ -493,25 +514,21 @@ class SlidableState extends State<Slidable>
493514 ..addStatusListener (_handleShowAllActionsStatusChanged);
494515 }
495516
496- void _handleShowAllActionsStatusChanged (AnimationStatus status) {
497- if (status == AnimationStatus .completed && ! _dragUnderway && ! _opening) {
498- _dragExtent = .0 ;
499- }
500-
501- if (status == AnimationStatus .completed) {
502- setState (() {});
503- }
504- }
505-
506517 AnimationController _controller;
518+
507519 double _dragExtent = 0.0 ;
508- bool _dragUnderway = false ;
509- bool _opening = false ;
520+
521+ ScrollPosition _scrollPosition ;
510522
511523 bool get _showActions {
512524 return _dragExtent > 0 ;
513525 }
514526
527+ @override
528+ bool get wantKeepAlive =>
529+ _controller != null &&
530+ (_controller.isAnimating || _controller.isCompleted);
531+
515532 /// The current actions that have to be shown.
516533 SlideActionDelegate get actionDelegate =>
517534 _showActions ? widget.actionDelegate : widget.secondaryActionDelegate;
@@ -526,14 +543,62 @@ class SlidableState extends State<Slidable>
526543 (actionDelegate? .actionCount ?? 0 );
527544 }
528545
546+ @override
547+ void didChangeDependencies () {
548+ super .didChangeDependencies ();
549+ _removeScrollingNotifierListener ();
550+ _addScrollingNotifierListener ();
551+ }
552+
553+ @override
554+ void didUpdateWidget (Slidable oldWidget) {
555+ super .didUpdateWidget (oldWidget);
556+
557+ if (widget.closeOnScroll != oldWidget.closeOnScroll) {
558+ _removeScrollingNotifierListener ();
559+ _addScrollingNotifierListener ();
560+ }
561+ }
562+
563+ void _addScrollingNotifierListener () {
564+ if (widget.closeOnScroll) {
565+ _scrollPosition = Scrollable .of (context)? .position;
566+ if (_scrollPosition != null )
567+ _scrollPosition.isScrollingNotifier.addListener (_isScrollingListener);
568+ }
569+ }
570+
571+ void _removeScrollingNotifierListener () {
572+ if (_scrollPosition != null ) {
573+ _scrollPosition.isScrollingNotifier.removeListener (_isScrollingListener);
574+ }
575+ }
576+
529577 @override
530578 void dispose () {
531579 _controller.dispose ();
580+ _removeScrollingNotifierListener ();
532581 super .dispose ();
533582 }
534583
584+ void open () {
585+ _controller.fling (velocity: 1.0 );
586+ }
587+
588+ void close () {
589+ _controller.fling (velocity: - 1.0 );
590+ }
591+
592+ void _isScrollingListener () {
593+ if (! widget.closeOnScroll || _scrollPosition == null ) return ;
594+
595+ // When a scroll starts close this.
596+ if (_scrollPosition.isScrollingNotifier.value) {
597+ close ();
598+ }
599+ }
600+
535601 void _handleDragStart (DragStartDetails details) {
536- _dragUnderway = true ;
537602 _dragExtent = _controller.value * _overallDragAxisExtent * _dragExtent.sign;
538603 if (_controller.isAnimating) {
539604 _controller.stop ();
@@ -549,21 +614,23 @@ class SlidableState extends State<Slidable>
549614 }
550615
551616 void _handleDragEnd (DragEndDetails details) {
552- _dragUnderway = false ;
553617 final double velocity = details.primaryVelocity;
554- final bool open = velocity.sign == _dragExtent.sign;
618+ final bool shouldOpen = velocity.sign == _dragExtent.sign;
555619 final bool fast = velocity.abs () > widget.delegate.fastThreshold;
556- if (! open && fast) {
557- _opening = false ;
558- _controller.animateTo (0.0 );
559- } else if (_controller.value >= widget.showAllActionsThreshold ||
560- (open && fast)) {
561- _opening = true ;
562- _controller.animateTo (1.0 );
620+ if (_controller.value >= widget.showAllActionsThreshold ||
621+ (shouldOpen && fast)) {
622+ open ();
563623 } else {
564- _opening = false ;
565- _controller.animateTo (0.0 );
624+ close ();
625+ }
626+ }
627+
628+ void _handleShowAllActionsStatusChanged (AnimationStatus status) {
629+ if (status == AnimationStatus .completed) {
630+ setState (() {});
566631 }
632+
633+ updateKeepAlive ();
567634 }
568635
569636 @override
@@ -590,7 +657,7 @@ class SlidableState extends State<Slidable>
590657 new SlidableDelegateContext (
591658 widget,
592659 _showActions,
593- _dragExtent,
660+ _dragExtent.sign ,
594661 _controller,
595662 ),
596663 );
@@ -607,7 +674,4 @@ class SlidableState extends State<Slidable>
607674 child: content,
608675 );
609676 }
610-
611- @override
612- bool get wantKeepAlive => _opening;
613677}
0 commit comments