Skip to content

Commit b0584c1

Browse files
authored
Merge pull request #18 from letsar/feature/slide_to_dismiss
Feature/slide to dismiss
2 parents 05c4e48 + 12006e0 commit b0584c1

File tree

6 files changed

+719
-132
lines changed

6 files changed

+719
-132
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,13 @@ doc/api/
1818
.idea/
1919
.DS_Store
2020
.vscode/
21+
22+
example/android/\.project
23+
24+
example/android/\.settings/org\.eclipse\.buildship\.core\.prefs
25+
26+
example/android/app/\.classpath
27+
28+
example/android/app/\.project
29+
30+
example/android/app/\.settings/org\.eclipse\.buildship\.core\.prefs

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## 0.4.0
2+
### Added
3+
* The `SlidableRenderingMode` enum.
4+
* The `SlideActionType` enum.
5+
* The `SlideToDismissDelegate` classes.
6+
7+
### Modified
8+
* Added a renderingMode parameter in the `SlideActionBuilder` signature .
9+
110
## 0.3.2
211
### Added
312
* The `enabled` argument on `Slidable` constructors to enable or disable the slide effect (enabled by default).

README.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# flutter_slidable
22

3-
A Flutter implementation of slidable list item with directional slide actions.
3+
A Flutter implementation of slidable list item with directional slide actions that can be dismissed.
44

55
[![Pub](https://img.shields.io/pub/v/flutter_slidable.svg)](https://pub.dartlang.org/packages/flutter_slidable)
66
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QTT34M25RDNL6)
@@ -10,8 +10,10 @@ A Flutter implementation of slidable list item with directional slide actions.
1010
## Features
1111

1212
* Accepts left and right widget lists as slide actions.
13+
* Can be dismissed.
1314
* 4 built-in layouts.
1415
* 2 built-in slide action widgets.
16+
* 1 built-in dismiss animation.
1517
* You can easily create you custom layouts and animations.
1618
* You can use a builder to create your slide actions if you want special effects during animation.
1719
* Close when a slide action has been tapped (overridable).
@@ -25,7 +27,7 @@ In the `pubspec.yaml` of your flutter project, add the following dependency:
2527
```yaml
2628
dependencies:
2729
...
28-
flutter_slidable: "^0.3.2"
30+
flutter_slidable: "^0.4.0"
2931
```
3032
3133
In your library add the following import:
@@ -138,12 +140,82 @@ The slide actions stretch while the item is sliding:
138140
#### How to prevent my slide action to close after it has been tapped?
139141

140142
By default, `SlideAction` and `IconSlideAction` close on tap.
141-
To prevent this, you can pass in `false` to the `closeOnTap` constructor argument.
143+
To prevent this, you can pass in `false` to the `closeOnTap` constructor argument.
142144

143145
#### How to prevent my Slidable to close after my list has scrolled?
144146

145147
By default, a `Slidable` closes when the nearest `Scrollable` widget starts to scroll.
146-
To prevent this, you can pass in `false` to the `closeOnScroll` constructor argument.
148+
To prevent this, you can pass in `false` to the `closeOnScroll` constructor argument.
149+
150+
#### How can I dismiss my Slidable?
151+
152+
In order to make your `Slidable` dismissible, you have to set the `slideToDismissDelegate` argument of the `Slidable` constructor.
153+
You can set any class that inherits `SlideToDismissDelegate`. For now there is only one built-in: `SlideToDismissDrawerDelegate`.
154+
155+
The `actionType` passed to the `onDismissed` callback let you know which action has been dismissed.
156+
157+
When a `Slidable` is dismissible, the `key` argument must not be null.
158+
159+
Example:
160+
161+
``` dart
162+
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
163+
onDismissed: (actionType) {
164+
_showSnackBar(
165+
context,
166+
actionType == SlideActionType.primary
167+
? 'Dismiss Archive'
168+
: 'Dimiss Delete');
169+
setState(() {
170+
items.removeAt(index);
171+
});
172+
},
173+
),
174+
```
175+
176+
#### How can I prevent to dismiss one side but not the other?
177+
178+
If you only want one side to be dismissible, you can set the associated threshold to 1.0 or more.
179+
For example, if you don't want the first primary action to be dismissed, you will set the following thresholds on the `slideToDismissDelegate`:
180+
181+
``` dart
182+
dismissThresholds: <SlideActionType, double>{
183+
SlideActionType.primary: 1.0
184+
},
185+
```
186+
187+
#### How to let the user cancel a dismissal?
188+
189+
You can let the user confirm the dismissal by setting the `onWillDismiss` callback on the `slideToDismissDelegate`.
190+
191+
Example:
192+
193+
```dart
194+
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
195+
onWillDismiss: (actionType) {
196+
return showDialog<bool>(
197+
context: context,
198+
builder: (context) {
199+
return new AlertDialog(
200+
title: new Text('Delete'),
201+
content: new Text('Item will be deleted'),
202+
actions: <Widget>[
203+
new FlatButton(
204+
child: new Text('Cancel'),
205+
onPressed: () => Navigator.of(context).pop(false),
206+
),
207+
new FlatButton(
208+
child: new Text('Ok'),
209+
onPressed: () => Navigator.of(context).pop(true),
210+
),
211+
],
212+
);
213+
},
214+
);
215+
},
216+
...
217+
),
218+
```
147219

148220
## Changelog
149221

example/lib/main.dart

Lines changed: 110 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ class MyHomePage extends StatefulWidget {
2727
}
2828

2929
class _MyHomePageState extends State<MyHomePage> {
30+
final List<_HomeItem> items = List.generate(
31+
20,
32+
(i) => new _HomeItem(
33+
i,
34+
'Tile n°$i',
35+
_getSubtitle(i),
36+
_getAvatarColor(i),
37+
),
38+
);
39+
3040
@override
3141
Widget build(BuildContext context) {
3242
return new Scaffold(
@@ -45,32 +55,35 @@ class _MyHomePageState extends State<MyHomePage> {
4555
itemBuilder: (context, index) {
4656
final Axis slidableDirection =
4757
direction == Axis.horizontal ? Axis.vertical : Axis.horizontal;
48-
if (index < 8) {
58+
var item = items[index];
59+
if (item.index < 8) {
4960
return _getSlidableWithLists(context, index, slidableDirection);
5061
} else {
5162
return _getSlidableWithDelegates(context, index, slidableDirection);
5263
}
5364
},
54-
itemCount: 20,
65+
itemCount: items.length,
5566
);
5667
}
5768

5869
Widget _buildVerticalListItem(BuildContext context, int index) {
70+
final _HomeItem item = items[index];
5971
return new Container(
6072
color: Colors.white,
6173
child: new ListTile(
6274
leading: new CircleAvatar(
63-
backgroundColor: _getAvatarColor(index),
64-
child: new Text('$index'),
75+
backgroundColor: item.color,
76+
child: new Text('${item.index}'),
6577
foregroundColor: Colors.white,
6678
),
67-
title: new Text('Tile n°$index'),
68-
subtitle: new Text(_getSubtitle(index)),
79+
title: new Text(item.title),
80+
subtitle: new Text(item.subtitle),
6981
),
7082
);
7183
}
7284

7385
Widget _buildhorizontalListItem(BuildContext context, int index) {
86+
final _HomeItem item = items[index];
7487
return new Container(
7588
color: Colors.white,
7689
width: 160.0,
@@ -79,15 +92,15 @@ class _MyHomePageState extends State<MyHomePage> {
7992
children: <Widget>[
8093
new Expanded(
8194
child: new CircleAvatar(
82-
backgroundColor: _getAvatarColor(index),
83-
child: new Text('$index'),
95+
backgroundColor: item.color,
96+
child: new Text('${item.index}'),
8497
foregroundColor: Colors.white,
8598
),
8699
),
87100
new Expanded(
88101
child: Center(
89102
child: new Text(
90-
_getSubtitle(index),
103+
item.subtitle,
91104
),
92105
),
93106
),
@@ -98,9 +111,24 @@ class _MyHomePageState extends State<MyHomePage> {
98111

99112
Widget _getSlidableWithLists(
100113
BuildContext context, int index, Axis direction) {
114+
final _HomeItem item = items[index];
115+
//final int t = index;
101116
return new Slidable(
117+
key: new Key(item.title),
102118
direction: direction,
103-
delegate: _getDelegate(index),
119+
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
120+
onDismissed: (actionType) {
121+
_showSnackBar(
122+
context,
123+
actionType == SlideActionType.primary
124+
? 'Dismiss Archive'
125+
: 'Dimiss Delete');
126+
setState(() {
127+
items.removeAt(index);
128+
});
129+
},
130+
),
131+
delegate: _getDelegate(item.index),
104132
actionExtentRatio: 0.25,
105133
child: direction == Axis.horizontal
106134
? _buildVerticalListItem(context, index)
@@ -139,47 +167,95 @@ class _MyHomePageState extends State<MyHomePage> {
139167

140168
Widget _getSlidableWithDelegates(
141169
BuildContext context, int index, Axis direction) {
170+
final _HomeItem item = items[index];
171+
142172
return new Slidable.builder(
173+
key: new Key(item.title),
143174
direction: direction,
144-
delegate: _getDelegate(index),
175+
slideToDismissDelegate: new SlideToDismissDrawerDelegate(
176+
onWillDismiss: (item.index != 10)
177+
? null
178+
: (actionType) {
179+
return showDialog<bool>(
180+
context: context,
181+
builder: (context) {
182+
return new AlertDialog(
183+
title: new Text('Delete'),
184+
content: new Text('Item will be deleted'),
185+
actions: <Widget>[
186+
new FlatButton(
187+
child: new Text('Cancel'),
188+
onPressed: () => Navigator.of(context).pop(false),
189+
),
190+
new FlatButton(
191+
child: new Text('Ok'),
192+
onPressed: () => Navigator.of(context).pop(true),
193+
),
194+
],
195+
);
196+
},
197+
);
198+
},
199+
onDismissed: (actionType) {
200+
_showSnackBar(
201+
context,
202+
actionType == SlideActionType.primary
203+
? 'Dismiss Archive'
204+
: 'Dimiss Delete');
205+
setState(() {
206+
items.removeAt(index);
207+
});
208+
},
209+
),
210+
delegate: _getDelegate(item.index),
145211
actionExtentRatio: 0.25,
146212
child: direction == Axis.horizontal
147213
? _buildVerticalListItem(context, index)
148214
: _buildhorizontalListItem(context, index),
149215
actionDelegate: new SlideActionBuilderDelegate(
150216
actionCount: 2,
151-
builder: (context, index, animation) {
217+
builder: (context, index, animation, renderingMode) {
152218
if (index == 0) {
153219
return new IconSlideAction(
154220
caption: 'Archive',
155-
color: Colors.blue.withOpacity(animation.value),
221+
color: renderingMode == SlidableRenderingMode.slide
222+
? Colors.blue.withOpacity(animation.value)
223+
: (renderingMode == SlidableRenderingMode.dismiss
224+
? Colors.blue
225+
: Colors.green),
156226
icon: Icons.archive,
157227
onTap: () => _showSnackBar(context, 'Archive'),
158228
);
159229
} else {
160230
return new IconSlideAction(
161231
caption: 'Share',
162-
color: Colors.indigo.withOpacity(animation.value),
232+
color: renderingMode == SlidableRenderingMode.slide
233+
? Colors.indigo.withOpacity(animation.value)
234+
: Colors.indigo,
163235
icon: Icons.share,
164236
onTap: () => _showSnackBar(context, 'Share'),
165237
);
166238
}
167239
}),
168240
secondaryActionDelegate: new SlideActionBuilderDelegate(
169241
actionCount: 2,
170-
builder: (context, index, animation) {
242+
builder: (context, index, animation, renderingMode) {
171243
if (index == 0) {
172244
return new IconSlideAction(
173245
caption: 'More',
174-
color: Colors.grey.shade200.withOpacity(animation.value),
246+
color: renderingMode == SlidableRenderingMode.slide
247+
? Colors.grey.shade200.withOpacity(animation.value)
248+
: Colors.grey.shade200,
175249
icon: Icons.more_horiz,
176250
onTap: () => _showSnackBar(context, 'More'),
177251
closeOnTap: false,
178252
);
179253
} else {
180254
return new IconSlideAction(
181255
caption: 'Delete',
182-
color: Colors.red.withOpacity(animation.value),
256+
color: renderingMode == SlidableRenderingMode.slide
257+
? Colors.red.withOpacity(animation.value)
258+
: Colors.red,
183259
icon: Icons.delete,
184260
onTap: () => _showSnackBar(context, 'Delete'),
185261
);
@@ -188,7 +264,7 @@ class _MyHomePageState extends State<MyHomePage> {
188264
);
189265
}
190266

191-
SlidableDelegate _getDelegate(int index) {
267+
static SlidableDelegate _getDelegate(int index) {
192268
switch (index % 4) {
193269
case 0:
194270
return new SlidableBehindDelegate();
@@ -203,7 +279,7 @@ class _MyHomePageState extends State<MyHomePage> {
203279
}
204280
}
205281

206-
Color _getAvatarColor(int index) {
282+
static Color _getAvatarColor(int index) {
207283
switch (index % 4) {
208284
case 0:
209285
return Colors.red;
@@ -218,7 +294,7 @@ class _MyHomePageState extends State<MyHomePage> {
218294
}
219295
}
220296

221-
String _getSubtitle(int index) {
297+
static String _getSubtitle(int index) {
222298
switch (index % 4) {
223299
case 0:
224300
return 'SlidableBehindDelegate';
@@ -237,3 +313,17 @@ class _MyHomePageState extends State<MyHomePage> {
237313
Scaffold.of(context).showSnackBar(SnackBar(content: new Text(text)));
238314
}
239315
}
316+
317+
class _HomeItem {
318+
const _HomeItem(
319+
this.index,
320+
this.title,
321+
this.subtitle,
322+
this.color,
323+
);
324+
325+
final int index;
326+
final String title;
327+
final String subtitle;
328+
final Color color;
329+
}

0 commit comments

Comments
 (0)