Skip to content

Commit

Permalink
add a callback to confirm the dismissal
Browse files Browse the repository at this point in the history
  • Loading branch information
letsar committed Jul 31, 2018
1 parent bd1c0e8 commit 12006e0
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 6 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,13 @@ doc/api/
.idea/
.DS_Store
.vscode/

example/android/\.project

example/android/\.settings/org\.eclipse\.buildship\.core\.prefs

example/android/app/\.classpath

example/android/app/\.project

example/android/app/\.settings/org\.eclipse\.buildship\.core\.prefs
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ By default, a `Slidable` closes when the nearest `Scrollable` widget starts to s
To prevent this, you can pass in `false` to the `closeOnScroll` constructor argument.

#### How can I dismiss my Slidable?

In order to make your `Slidable` dismissible, you have to set the `slideToDismissDelegate` argument of the `Slidable` constructor.
You can set any class that inherits `SlideToDismissDelegate`. For now there is only one built-in: `SlideToDismissDrawerDelegate`.

Expand All @@ -173,6 +174,7 @@ slideToDismissDelegate: new SlideToDismissDrawerDelegate(
```

#### How can I prevent to dismiss one side but not the other?

If you only want one side to be dismissible, you can set the associated threshold to 1.0 or more.
For example, if you don't want the first primary action to be dismissed, you will set the following thresholds on the `slideToDismissDelegate`:

Expand All @@ -182,6 +184,39 @@ dismissThresholds: <SlideActionType, double>{
},
```

#### How to let the user cancel a dismissal?

You can let the user confirm the dismissal by setting the `onWillDismiss` callback on the `slideToDismissDelegate`.

Example:

```dart
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
onWillDismiss: (actionType) {
return showDialog<bool>(
context: context,
builder: (context) {
return new AlertDialog(
title: new Text('Delete'),
content: new Text('Item will be deleted'),
actions: <Widget>[
new FlatButton(
child: new Text('Cancel'),
onPressed: () => Navigator.of(context).pop(false),
),
new FlatButton(
child: new Text('Ok'),
onPressed: () => Navigator.of(context).pop(true),
),
],
);
},
);
},
...
),
```

## Changelog

Please see the [Changelog](https://github.com/letsar/flutter_slidable/blob/master/CHANGELOG.md) page to know what's recently changed.
Expand Down
44 changes: 41 additions & 3 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class _MyHomePageState extends State<MyHomePage> {
itemBuilder: (context, index) {
final Axis slidableDirection =
direction == Axis.horizontal ? Axis.vertical : Axis.horizontal;
if (index < 8) {
var item = items[index];
if (item.index < 8) {
return _getSlidableWithLists(context, index, slidableDirection);
} else {
return _getSlidableWithDelegates(context, index, slidableDirection);
Expand Down Expand Up @@ -111,10 +112,23 @@ class _MyHomePageState extends State<MyHomePage> {
Widget _getSlidableWithLists(
BuildContext context, int index, Axis direction) {
final _HomeItem item = items[index];
//final int t = index;
return new Slidable(
key: new Key(item.title),
direction: direction,
delegate: _getDelegate(index),
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
onDismissed: (actionType) {
_showSnackBar(
context,
actionType == SlideActionType.primary
? 'Dismiss Archive'
: 'Dimiss Delete');
setState(() {
items.removeAt(index);
});
},
),
delegate: _getDelegate(item.index),
actionExtentRatio: 0.25,
child: direction == Axis.horizontal
? _buildVerticalListItem(context, index)
Expand Down Expand Up @@ -154,10 +168,34 @@ class _MyHomePageState extends State<MyHomePage> {
Widget _getSlidableWithDelegates(
BuildContext context, int index, Axis direction) {
final _HomeItem item = items[index];

return new Slidable.builder(
key: new Key(item.title),
direction: direction,
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
onWillDismiss: (item.index != 10)
? null
: (actionType) {
return showDialog<bool>(
context: context,
builder: (context) {
return new AlertDialog(
title: new Text('Delete'),
content: new Text('Item will be deleted'),
actions: <Widget>[
new FlatButton(
child: new Text('Cancel'),
onPressed: () => Navigator.of(context).pop(false),
),
new FlatButton(
child: new Text('Ok'),
onPressed: () => Navigator.of(context).pop(true),
),
],
);
},
);
},
onDismissed: (actionType) {
_showSnackBar(
context,
Expand All @@ -169,7 +207,7 @@ class _MyHomePageState extends State<MyHomePage> {
});
},
),
delegate: _getDelegate(index),
delegate: _getDelegate(item.index),
actionExtentRatio: 0.25,
child: direction == Axis.horizontal
? _buildVerticalListItem(context, index)
Expand Down
28 changes: 25 additions & 3 deletions lib/src/widgets/slidable.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

Expand Down Expand Up @@ -33,11 +35,17 @@ enum SlideActionType {
}

/// Signature used by [SlideToDismissDelegate] to indicate that it has been
/// dismissed for the given `actionType`.
/// dismissed for the given [actionType].
///
/// Used by [SlideToDismissDelegate.onDismissed].
typedef void DismissSlideActionCallback(SlideActionType actionType);

/// Signature for determining whether the widget will be dismissed for the
/// given [actionType].
///
/// Used by [SlideToDismissDelegate.onWillDismiss].
typedef FutureOr<bool> SlideActionWillBeDismissed(SlideActionType actionType);

/// Signature for the builder callback used to create slide actions.
typedef Widget SlideActionBuilder(BuildContext context, int index,
Animation<double> animation, SlidableRenderingMode step);
Expand All @@ -61,6 +69,7 @@ abstract class SlideToDismissDelegate {
this.onDismissed,
this.resizeDuration: _kResizeDuration,
this.crossAxisEndOffset: 0.0,
this.onWillDismiss,
}) : assert(dismissThresholds != null);

/// The offset threshold the item has to be dragged in order to be considered
Expand All @@ -81,6 +90,12 @@ abstract class SlideToDismissDelegate {
/// Called when the widget has been dismissed, after finishing resizing.
final DismissSlideActionCallback onDismissed;

/// Called before the widget is dismissed. If the call returns false, the
/// item will not be dismissed.
///
/// If null, the widget will always be dismissed.
final SlideActionWillBeDismissed onWillDismiss;

/// Called when the widget changes size (i.e., when contracting before being dismissed).
final VoidCallback onResize;

Expand Down Expand Up @@ -120,12 +135,14 @@ class SlideToDismissDrawerDelegate extends SlideToDismissDelegate {
DismissSlideActionCallback onDismissed,
Duration resizeDuration: _kResizeDuration,
double crossAxisEndOffset: 0.0,
SlideActionWillBeDismissed onWillDismiss,
}) : super(
dismissThresholds: dismissThresholds,
onResize: onResize,
onDismissed: onDismissed,
resizeDuration: resizeDuration,
crossAxisEndOffset: crossAxisEndOffset,
onWillDismiss: onWillDismiss,
);

Widget buildActionsWhileDismissing(
Expand Down Expand Up @@ -949,12 +966,17 @@ class SlidableState extends State<Slidable>
updateKeepAlive();
}

void _handleDismissStatusChanged(AnimationStatus status) {
void _handleDismissStatusChanged(AnimationStatus status) async {
if (dismissible) {
if (status == AnimationStatus.completed &&
_overallMoveController.value == _overallMoveController.upperBound &&
!_dragUnderway) {
_startResizeAnimation();
if (widget.slideToDismissDelegate.onWillDismiss == null ||
await widget.slideToDismissDelegate.onWillDismiss(actionType)) {
_startResizeAnimation();
} else {
open();
}
}
updateKeepAlive();
}
Expand Down

0 comments on commit 12006e0

Please sign in to comment.