有一天前,我决定从Pinterest为应用程序选择一个Ui来练习使用Flutter构建应用程序但我仍然坚持使用Slider,它在水平拖动时显示“更多”和“删除”按钮。 Picture on the right
我没有足够的知识来使用手势与动画相结合来创建这样的东西。这就是为什么我希望你们中的某个人可以为像我这样的人做一个例子,我们可以理解如何在ListView.builder中实现这样的东西。
来自macOS邮件App的gif示例:
答案 0 :(得分:29)
我创建了一个用于进行这种布局的程序包:flutter_slidable(感谢RémiRousselet的基本想法)
使用此软件包,可以更轻松地为列表项创建上下文操作。例如,如果要创建描述的动画类型:
您将使用以下代码:
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'),
),
],
);
答案 1 :(得分:21)
已经有了这种手势的小部件。它被称为Dismissible
。
你可以在这里找到它。 https://docs.flutter.io/flutter/widgets/Dismissible-class.html
修改强>
如果你需要完全相同的转换,你可能必须自己实施。 我做了一个基本的例子。你可能想稍微调整动画,但它至少有效。
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(),
),
),
),
],
);
},
);
},
),
)
],
),
);
}
}
修改强>
Flutter不再允许Animation<FractionalOffset>
SlideTransition
属性中的animation
类型。根据这篇文章https://groups.google.com/forum/#!topic/flutter-dev/fmr-C9xK5t4,它应该替换为AlignmentTween
,但这也不起作用。相反,根据此问题:https://github.com/flutter/flutter/issues/13812将其替换为原始Tween
并直接创建Offset
对象。不幸的是,代码不太清楚。
答案 2 :(得分:1)
Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: the_length_of_your_items,
itemBuilder: (BuildContext context,int index) {
return Slidable(
actionPane: SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
child: Container(
color: Colors.white,
child: ListTile(
leading: Text(('the_leading')),
title: Text(('the_title')),
trailing: Text(('the_trailing')),
subtitle: Text(('the_subtitle')),
),
),
actions: <Widget>[
IconSlideAction(
caption: 'Archive',
color: Colors.blue,
icon: Icons.archive,
onTap: () {print('archive');},
),
IconSlideAction(
caption: 'Share',
color: Colors.indigo,
icon: Icons.share,
onTap: () {print('share');},
),
],
secondaryActions: <Widget>[
IconSlideAction(
caption: 'More',
color: Colors.black45,
icon: Icons.more_horiz,
onTap: () {print('more');},
),
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () {print('delete');},
),
],
);
}),
),
答案 3 :(得分:0)