@@ -107,7 +107,7 @@ class SlidableDelegateContext {
107
107
const SlidableDelegateContext (
108
108
this .slidable,
109
109
this .showActions,
110
- this .dragExtent ,
110
+ this .dragSign ,
111
111
this .controller,
112
112
);
113
113
@@ -126,7 +126,7 @@ class SlidableDelegateContext {
126
126
/// Whether the actions have to be shown.
127
127
final bool showActions;
128
128
129
- final double dragExtent ;
129
+ final double dragSign ;
130
130
131
131
/// The animation controller which value depends on `dragExtent` .
132
132
final AnimationController controller;
@@ -199,10 +199,10 @@ abstract class SlidableStackDelegate extends SlidableDelegate {
199
199
Widget buildActions (BuildContext context, SlidableDelegateContext ctx) {
200
200
final animation = new Tween (
201
201
begin: Offset .zero,
202
- end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragExtent.sign ),
202
+ end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragSign ),
203
203
).animate (ctx.controller);
204
204
205
- if (ctx.controller.value != .0 && ctx.dragExtent != . 0 ) {
205
+ if (ctx.controller.value != .0 ) {
206
206
return new Container (
207
207
child: new Stack (
208
208
children: < Widget > [
@@ -237,7 +237,7 @@ class SlidableStrechDelegate extends SlidableStackDelegate {
237
237
Widget buildStackActions (BuildContext context, SlidableDelegateContext ctx) {
238
238
final animation = new Tween (
239
239
begin: Offset .zero,
240
- end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragExtent.sign ),
240
+ end: ctx.createOffset (ctx.totalActionsExtent * ctx.dragSign ),
241
241
).animate (ctx.controller);
242
242
243
243
return new Positioned .fill (
@@ -395,12 +395,12 @@ class SlidableDrawerDelegate extends SlidableStackDelegate {
395
395
///
396
396
/// By sliding in one of these direction, slide actions will appear.
397
397
class Slidable extends StatefulWidget {
398
- /// Creates a widget that can be dismissed .
398
+ /// Creates a widget that can be slid .
399
399
///
400
400
/// The [actions] contains the slide actions that appears when the child has been dragged down or to the right.
401
401
/// The [secondaryActions] contains the slide actions that appears when the child has been dragged up or to the left.
402
402
///
403
- /// The [delegate] argument must not be null. The [actionExtentRatio]
403
+ /// The [delegate] and [closeOnScroll] arguments must not be null. The [actionExtentRatio]
404
404
/// and [showAllActionsThreshold] arguments must be greater or equal than 0 and less or equal than 1.
405
405
Slidable ({
406
406
Key key,
@@ -412,6 +412,7 @@ class Slidable extends StatefulWidget {
412
412
double actionExtentRatio = _kActionsExtentRatio,
413
413
Duration movementDuration = const Duration (milliseconds: 200 ),
414
414
Axis direction = Axis .horizontal,
415
+ bool closeOnScroll = true ,
415
416
}) : this .builder (
416
417
key: key,
417
418
child: child,
@@ -423,8 +424,16 @@ class Slidable extends StatefulWidget {
423
424
actionExtentRatio: actionExtentRatio,
424
425
movementDuration: movementDuration,
425
426
direction: direction,
427
+ closeOnScroll: closeOnScroll,
426
428
);
427
429
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.
428
437
Slidable .builder ({
429
438
Key key,
430
439
@required this .child,
@@ -435,6 +444,7 @@ class Slidable extends StatefulWidget {
435
444
this .actionExtentRatio = _kActionsExtentRatio,
436
445
this .movementDuration = const Duration (milliseconds: 200 ),
437
446
this .direction = Axis .horizontal,
447
+ this .closeOnScroll = true ,
438
448
}) : assert (delegate != null ),
439
449
assert (direction != null ),
440
450
assert (
@@ -447,6 +457,7 @@ class Slidable extends StatefulWidget {
447
457
actionExtentRatio >= .0 &&
448
458
actionExtentRatio <= 1.0 ,
449
459
'actionExtentRatio must be between 0.0 and 1.0' ),
460
+ assert (closeOnScroll != null ),
450
461
super (key: key);
451
462
452
463
/// The widget below this widget in the tree.
@@ -479,6 +490,16 @@ class Slidable extends StatefulWidget {
479
490
/// Defines the duration for card to go to final position or to come back to original position if threshold not reached.
480
491
final Duration movementDuration;
481
492
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
+
482
503
@override
483
504
SlidableState createState () => SlidableState ();
484
505
}
@@ -493,25 +514,21 @@ class SlidableState extends State<Slidable>
493
514
..addStatusListener (_handleShowAllActionsStatusChanged);
494
515
}
495
516
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
-
506
517
AnimationController _controller;
518
+
507
519
double _dragExtent = 0.0 ;
508
- bool _dragUnderway = false ;
509
- bool _opening = false ;
520
+
521
+ ScrollPosition _scrollPosition ;
510
522
511
523
bool get _showActions {
512
524
return _dragExtent > 0 ;
513
525
}
514
526
527
+ @override
528
+ bool get wantKeepAlive =>
529
+ _controller != null &&
530
+ (_controller.isAnimating || _controller.isCompleted);
531
+
515
532
/// The current actions that have to be shown.
516
533
SlideActionDelegate get actionDelegate =>
517
534
_showActions ? widget.actionDelegate : widget.secondaryActionDelegate;
@@ -526,14 +543,62 @@ class SlidableState extends State<Slidable>
526
543
(actionDelegate? .actionCount ?? 0 );
527
544
}
528
545
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
+
529
577
@override
530
578
void dispose () {
531
579
_controller.dispose ();
580
+ _removeScrollingNotifierListener ();
532
581
super .dispose ();
533
582
}
534
583
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
+
535
601
void _handleDragStart (DragStartDetails details) {
536
- _dragUnderway = true ;
537
602
_dragExtent = _controller.value * _overallDragAxisExtent * _dragExtent.sign;
538
603
if (_controller.isAnimating) {
539
604
_controller.stop ();
@@ -549,21 +614,23 @@ class SlidableState extends State<Slidable>
549
614
}
550
615
551
616
void _handleDragEnd (DragEndDetails details) {
552
- _dragUnderway = false ;
553
617
final double velocity = details.primaryVelocity;
554
- final bool open = velocity.sign == _dragExtent.sign;
618
+ final bool shouldOpen = velocity.sign == _dragExtent.sign;
555
619
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 ();
563
623
} 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 (() {});
566
631
}
632
+
633
+ updateKeepAlive ();
567
634
}
568
635
569
636
@override
@@ -590,7 +657,7 @@ class SlidableState extends State<Slidable>
590
657
new SlidableDelegateContext (
591
658
widget,
592
659
_showActions,
593
- _dragExtent,
660
+ _dragExtent.sign ,
594
661
_controller,
595
662
),
596
663
);
@@ -607,7 +674,4 @@ class SlidableState extends State<Slidable>
607
674
child: content,
608
675
);
609
676
}
610
-
611
- @override
612
- bool get wantKeepAlive => _opening;
613
677
}
0 commit comments