我正在制作一个图片库,我需要用户能够长按图片以显示一个弹出菜单,让他可以删除图片。
我的代码,到目前为止:
return GestureDetector(
onLongPress: () {
showMenu(
items: <PopupMenuEntry>[
PopupMenuItem(
value: this._index,
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text("Delete"),
],
),
)
],
context: context,
);
},
child: Image.memory(
this._asset.thumbData.buffer.asUint8List(),
fit: BoxFit.cover,
gaplessPlayback: true,
),
);
产生:
但是,当调用 longPress 函数时,我不知道如何完全删除图像的小部件。该怎么做?
最佳答案
OP 和 First Answerer 使用 PopupMenuButton
绕过了原始问题,这在他们的情况下运行良好。但我认为如何定位自己的菜单以及如何在不使用 PopupMenuButton
的情况下接收用户响应的更一般的问题值得回答,因为有时我们希望在一个自定义小部件,我们希望它出现在一些手势上,而不是简单的点击(例如,OP 的初衷是长按)。
我开始制作一个简单的应用程序来演示以下内容:
GestureDetector
捕捉长按showMenu()
显示弹出菜单,并将其定位在手指触摸的附近PopupMenuEntry
(常用的PopupMenuItem
只能代表一个值)结果是,当你长按一个大的黄色区域时,会出现一个弹出菜单,您可以在其中选择 +1
或 -1
,大number 会相应地增加或减少:
整个代码体跳到最后。评论被洒在那里解释我在做什么。这里有几点需要注意:
showMenu()
的 position
参数需要一些努力才能理解。它是一个 RelativeRect
,它表示较小的矩形如何定位在较大的矩形内。在我们的例子中,较大的矩形是整个屏幕,较小的矩形是触摸区域。 Flutter 根据这些规则定位弹出菜单(用简单的英语):
如果较小的矩形向较大矩形的左一半倾斜,弹出菜单将与较小矩形的左边缘对齐
如果较小的矩形向较大矩形的右一半倾斜,弹出菜单将与较小矩形的右边缘对齐
如果较小的矩形在中间,则哪个边获胜取决于语言的文本方向。如果使用英语和其他从左到右的语言,左边缘获胜,否则右边缘获胜。
引用 PopupMenuButton
's official implementation 来了解它如何使用 showMenu()
来显示菜单总是很有用的。
showMenu()
返回一个 Future
。使用 Future.then()
注册回调以处理用户选择。另一种选择是使用 await
。
请记住,PopupMenuEntry
是 StatefulWidget
的(子类)。您可以在其中布局任意数量的子小部件。这就是您在 PopupMenuEntry
中表示多个值的方式。如果你想让它代表两个值,只要让它包含两个按钮,不管你想布局它们。
要关闭弹出菜单,请使用 Navigator.pop()
。 Flutter 将弹出菜单视为较小的“页面”。当我们显示一个弹出菜单时,我们实际上是在将一个“页面”推送到导航器的堆栈中。要关闭一个弹出菜单,我们将它从堆栈中弹出,从而完成前面提到的Future
。
这里是完整的代码:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Popup Menu Usage',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Popup Menu Usage'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _count = 0;
var _tapPosition;
void _showCustomMenu() {
final RenderBox overlay = Overlay.of(context).context.findRenderObject();
showMenu(
context: context,
items: <PopupMenuEntry<int>>[PlusMinusEntry()],
position: RelativeRect.fromRect(
_tapPosition & const Size(40, 40), // smaller rect, the touch area
Offset.zero & overlay.size // Bigger rect, the entire screen
)
)
// This is how you handle user selection
.then<void>((int delta) {
// delta would be null if user taps on outside the popup menu
// (causing it to close without making selection)
if (delta == null) return;
setState(() {
_count = _count + delta;
});
});
// Another option:
//
// final delta = await showMenu(...);
//
// Then process `delta` however you want.
// Remember to make the surrounding function `async`, that is:
//
// void _showCustomMenu() async { ... }
}
void _storePosition(TapDownDetails details) {
_tapPosition = details.globalPosition;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
// This does not give the tap position ...
onLongPress: _showCustomMenu,
// Have to remember it on tap-down.
onTapDown: _storePosition,
child: Container(
color: Colors.amberAccent,
padding: const EdgeInsets.all(100.0),
child: Text(
'$_count',
style: const TextStyle(
fontSize: 100, fontWeight: FontWeight.bold),
),
),
),
],
),
),
);
}
}
class PlusMinusEntry extends PopupMenuEntry<int> {
@override
double height = 100;
// height doesn't matter, as long as we are not giving
// initialValue to showMenu().
@override
bool represents(int n) => n == 1 || n == -1;
@override
PlusMinusEntryState createState() => PlusMinusEntryState();
}
class PlusMinusEntryState extends State<PlusMinusEntry> {
void _plus1() {
// This is how you close the popup menu and return user selection.
Navigator.pop<int>(context, 1);
}
void _minus1() {
Navigator.pop<int>(context, -1);
}
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(child: FlatButton(onPressed: _plus1, child: Text('+1'))),
Expanded(child: FlatButton(onPressed: _minus1, child: Text('-1'))),
],
);
}
}
https://stackoverflow.com/questions/54300081/
相关文章:
listview - 如何通过 Flutter 中的 RaisedButton 传递/绑定(bind
flutter - 控制和禁用 flutter 中的下拉按钮?
sqlite - 如何在 Flutter 中使用 SQFlite 进行数据库查询
dart - 在 Dart 中向服务器发出多个独立请求的最佳方式
image - Flutter CircleAvatar backgroundImage没有填满圆圈
firebase - 如何在 Flutter 中从 Firebase Auth 获取用户 ID?
android - 如何设置 Flutter 应用的构建和版本号