Swipe List Item for more options (Flutter)
I created a package for doing this kind of layout: flutter_slidable (Thanks Rémi Rousselet for the based idea)
With this package it's easier to create contextual actions for a list item. For example if you want to create the kind of animation you described:
You will use this code:
new Slidable( delegate: new SlidableDrawerDelegate(), actionExtentRatio: 0.25, child: new Container( color: Colors.white, child: new ListTile( leading: new CircleAvatar( backgroundColor: Colors.indigoAccent, child: new Text('$3'), foregroundColor: Colors.white, ), title: new Text('Tile n°$3'), subtitle: new Text('SlidableDrawerDelegate'), ), ), actions: <Widget>[ new IconSlideAction( caption: 'Archive', color: Colors.blue, icon: Icons.archive, onTap: () => _showSnackBar('Archive'), ), new IconSlideAction( caption: 'Share', color: Colors.indigo, icon: Icons.share, onTap: () => _showSnackBar('Share'), ), ], secondaryActions: <Widget>[ new IconSlideAction( caption: 'More', color: Colors.black45, icon: Icons.more_horiz, onTap: () => _showSnackBar('More'), ), new IconSlideAction( caption: 'Delete', color: Colors.red, icon: Icons.delete, onTap: () => _showSnackBar('Delete'), ), ],);
There's already a widget for this kind of gesture. It's called Dismissible
.
You can find it here. https://docs.flutter.io/flutter/widgets/Dismissible-class.html
EDIT
If you need the exact same transtion, you'd probably have to implement if yourself.I made a basic example. You'd probably want to tweak the animation a bit, but it's working at least.
class Test extends StatefulWidget { @override _TestState createState() => new _TestState();}class _TestState extends State<Test> { double rating = 3.5; @override Widget build(BuildContext context) { return new Scaffold( body: new ListView( children: ListTile .divideTiles( context: context, tiles: new List.generate(42, (index) { return new SlideMenu( child: new ListTile( title: new Container(child: new Text("Drag me")), ), menuItems: <Widget>[ new Container( child: new IconButton( icon: new Icon(Icons.delete), ), ), new Container( child: new IconButton( icon: new Icon(Icons.info), ), ), ], ); }), ) .toList(), ), ); }}class SlideMenu extends StatefulWidget { final Widget child; final List<Widget> menuItems; SlideMenu({this.child, this.menuItems}); @override _SlideMenuState createState() => new _SlideMenuState();}class _SlideMenuState extends State<SlideMenu> with SingleTickerProviderStateMixin { AnimationController _controller; @override initState() { super.initState(); _controller = new AnimationController(vsync: this, duration: const Duration(milliseconds: 200)); } @override dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final animation = new Tween( begin: const Offset(0.0, 0.0), end: const Offset(-0.2, 0.0) ).animate(new CurveTween(curve: Curves.decelerate).animate(_controller)); return new GestureDetector( onHorizontalDragUpdate: (data) { // we can access context.size here setState(() { _controller.value -= data.primaryDelta / context.size.width; }); }, onHorizontalDragEnd: (data) { if (data.primaryVelocity > 2500) _controller.animateTo(.0); //close menu on fast swipe in the right direction else if (_controller.value >= .5 || data.primaryVelocity < -2500) // fully open if dragged a lot to left or on fast swipe to left _controller.animateTo(1.0); else // close if none of above _controller.animateTo(.0); }, child: new Stack( children: <Widget>[ new SlideTransition(position: animation, child: widget.child), new Positioned.fill( child: new LayoutBuilder( builder: (context, constraint) { return new AnimatedBuilder( animation: _controller, builder: (context, child) { return new Stack( children: <Widget>[ new Positioned( right: .0, top: .0, bottom: .0, width: constraint.maxWidth * animation.value.dx * -1, child: new Container( color: Colors.black26, child: new Row( children: widget.menuItems.map((child) { return new Expanded( child: child, ); }).toList(), ), ), ), ], ); }, ); }, ), ) ], ), ); }}
EDIT
Flutter no longer allows type Animation<FractionalOffset>
in SlideTransition
animation
property. According to this post https://groups.google.com/forum/#!topic/flutter-dev/fmr-C9xK5t4 it should be replaced with AlignmentTween
but this also doesn't work. Instead, according to this issue: https://github.com/flutter/flutter/issues/13812 replacing it instead with a raw Tween
and directly creating Offset
object works instead. Unfortunately, the code is much less clear.
I have a task that needs the same swipeable menu actions I tried answeres of Romain Rastel and Rémi Rousselet. but I have complex widget tree. the issue with that slideable solutions is they go on other widgets(to left widgets of listview). I found a batter solution here someone wrote a nice article medium and GitHub sample is here.