我有一个在按下按钮时显示的菜单,我希望能够在菜单外有Tap的情况下关闭菜单,就像常规的PopupMenuButton
一样。
我当前的解决方案是使用Stack
作为其子级之一的GestureDetector
作为检测抽头的方法,但是使用此解决方案,我的对齐方式由Stack
控制,我只想由菜单的父级而不是Stack
控制的对齐方式。
//part of the build method
return Stack(
fit: StackFit.expand,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
//Holds the list of menu items
menuContainer,
//button that displays the menu
floatingActionButton]
),
//Detects taps outside the menu
GestureDetector(onTap: (() => setVisibility(false))
)
]
);
答案 0 :(得分:1)
您可以使用自定义路由来实现此行为:
class CustomDialog extends PopupRoute {
@override
Color get barrierColor => Colors.transparent;
@override
bool get barrierDismissible => true;
@override
String get barrierLabel => null;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return _builder(context);
}
Widget _builder(BuildContext context) {
return Container();
}
@override
Duration get transitionDuration => Duration(milliseconds: 300);
}
barrierDismissible
替代指示在小部件外部检测到触摸时是否应将路由从堆栈中弹出。每当您想要显示菜单时,您都可以调用Navigator.of(context).push(CustomDialog())
。
此解决方案不允许菜单返回任何值,如果您需要从菜单中返回数据,则可以替代ModalRoute并获得类似的结果。
答案 1 :(得分:1)
bobajeff的答案对我有用,但是我发现使用覆盖不透明的吸气剂并将barrierColor吸气剂设置为null会更清洁。
class CustomDialog extends PageRoute {
@override
Color get barrierColor => null;
@override
bool get opaque => false;
@override
bool get maintainState => false;
@override
bool get barrierDismissible => true;
@override
String get barrierLabel => null;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return _builder(context);
}
Widget _builder(BuildContext context) {
return Container();
}
@override
Duration get transitionDuration => Duration(milliseconds: 300);
}
答案 2 :(得分:0)
Mariano Uvalle的答案不再起作用,因为他们在_buildModalBarrier中放入了一个断言,以检查是否将屏障颜色设置为透明。
我的解决方法是将/packages/flutter/lib/src/widgets/routes.dart
文件复制到我自己的/libs
文件夹中,并在line: 1226
处注释掉该断言
assert(barrierColor != _kTransparent);
还要替换顶部的这些非dart:
或package:
进口
import 'basic.dart';
import 'focus_manager.dart';
import 'focus_scope.dart';
import 'framework.dart';
import 'modal_barrier.dart';
import 'navigator.dart';
import 'overlay.dart';
import 'page_storage.dart';
import 'transitions.dart';
使用
import 'package:flutter/widgets.dart';
然后在我的应用中
import 'routes.dart' as my;
并使用他发布的Mariano Uvalle的class
。只有extend
才是my.PopupRoute
。
这并不完美,但是可以解决问题。
编辑: 我已经尝试了上面的ModalRoute版本,它也可以工作:
class CustomDialog extends my.ModalRoute<bool> {
@override
Color get barrierColor => Colors.transparent;
@override
bool get barrierDismissible => true;
@override
String get barrierLabel => null;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return _builder(context);
}
Widget _builder(BuildContext context) {
return Container(alignment: Alignment.bottomLeft,
child: Container(height: kToolbarHeight,
child: Material(elevation: 8.0,
child:
Wrap(
children: <Widget>[
ListTile(
leading: new Icon(Icons.add_photo_alternate),
title: new Text('Add Image'),
onTap: () {
Navigator.pop(context, true);
},
)
],
),
),
),
);
}
@override
Duration get transitionDuration => Duration(milliseconds: 300);
@override
bool get maintainState => false;
@override
bool get opaque => false;
}
然后我将其设为压缩值:
onPressed: () async {
bool notDismissed = await Navigator.of(context).push(CustomDialog());
if (notDismissed == true)
{
print('user clicke option');
}
else {
print('dismissed dialog');
}
同样,它并不完美,但有时可能会派上用场。但是,我发现我确实需要针对我的用例检测对特定小部件的点击。