flutter - 如何关闭 Flutter 中的打开下拉菜单?
问题描述
我的屏幕上有一个下拉菜单,每次用户最小化应用程序时我都想关闭它(暂停状态)。我查看了 DropDownButton 小部件,它似乎使用 Navigator.push() 方法,所以如果我没记错的话,理想情况下应该使用 Navigator.pop() 将其关闭。
这是我已经尝试过的-
- 使用全局键获取下拉小部件的上下文并实现
Navigator.pop(key.currentContext)
内部didChangeAppLifecycleState()
功能。 - 使用 focusNode 来实现
.unfocus()
从下拉列表中移除焦点。 - 维护一个我设置为on和on的
isDropdownDialogOpen
布尔值。然后很简单,如果它在应用程序最小化。但是当用户打开下拉菜单然后通过在下拉对话框外部点击将其关闭时,这种方法会失败。在这种情况下,我无法将布尔值设置为。true
onTap()
false
onChange()
pop()
true
false
我的要求是 - 每当用户最小化应用程序时,我必须关闭下拉菜单,如果它首先打开的话。
我经历了一堆 SO 问题和 GitHub 评论,它们甚至很相似,但找不到任何有用的东西。
松散代码 -
class Auth extends State<Authentication> with WidgetsBindingObserver {
bool isDropdownOpen = false;
GlobalKey _dropdownKey = GlobalKey();
FocusNode _focusNode;
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
// To pop the open dropdown dialog whenever app is minimised (and opened back on again)
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
if(isDropdownOpen)
pop();
// Also tried pop(_dropdownKey.currentContext)
break;
case AppLifecycleState.paused:
break;
case AppLifecycleState.inactive:
break;
case AppLifecycleState.detached:
break;
}
}
build() {
return Scaffold(
// Dummy Dropdown button with random values
body: DropdownButton(
key: _dropdownKey,
focusNode: _focusNode,
value: "one",
items: ["one", "two", "three", "four", "five"],
//boolean values changing fine, but when user taps outside the dropdown dialog, dropdown is closed and neither of onChanged() and onTap() is called. Need a call back (or something similar) for this particular case.
onChange(value) => isDropdownOpen = false;
onTap() => isDropdownOpen = ! isDropdownOpen;
)
);
}
}
解决方案
这对你有用吗?
import 'package:flutter/material.dart';
void main() async {
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key key}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
AppLifecycleState currentAppLifecycleState;
bool isDropdownMenuShown = false;
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(
() => currentAppLifecycleState = state,
);
}
String value;
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (<AppLifecycleState>[
AppLifecycleState.inactive,
AppLifecycleState.detached,
AppLifecycleState.paused,
].contains(currentAppLifecycleState) &&
isDropdownMenuShown) {
print('Closing dropdown');
Navigator.pop(context);
}
});
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: Center(
child: GestureDetector(
onLongPressStart: (LongPressStartDetails details) async {
final left = details.globalPosition.dx;
final top = details.globalPosition.dy;
setState(() => isDropdownMenuShown = true);
final value = await showMenu<String>(
context: context,
position: RelativeRect.fromLTRB(left, top, left, top),
items: <PopupMenuEntry<String>>[
PopupMenuItem(
child: const Text('Option 1'),
value: 'Option 1',
),
PopupMenuItem(
child: const Text('Option 2'),
value: 'Option 2',
),
PopupMenuItem(
child: const Text('Option 3'),
value: 'Option 3',
),
],
);
setState(() => isDropdownMenuShown = false);
if (value == null) return;
print('You chose: $value');
},
child: InkWell(
onTap: () {},
child: Container(
alignment: Alignment.center,
child: Text(
'Long press to show dropdown',
textAlign: TextAlign.center,
),
),
),
),
),
);
}
}
它是如何工作的?
didChangeAppLifecycleState
我们使用该方法跟踪当前的应用程序状态。
每当显示下拉菜单时,isDropdownMenuShown
变量就会设置为true
. 每当下拉菜单关闭/退出时,变量都会设置为false
.
我们添加一个后帧回调(在每次重建后调用),并检查应用程序是否进入后台以及是否显示下拉菜单。如果是,则关闭下拉菜单。
推荐阅读
- macos - 使用特权帮助工具在 mac os 上发布应用程序
- java - 使用 JDBCTemplate 的 JDBC 查询结果流
- swift - 让应用程序不接管菜单栏但仍有停靠图标?
- knockout.js - 淘汰嵌套的 $componentTemplateNodes 返回错误的上下文节点?
- dataframe - Pyspark - 使用列表中的startswith创建一个新列
- f# - 如何将复杂的 Application Insights 引入 Farmer 部署?
- python - SqlAlchemy 函数元素。如何在课堂上放方法?
- .net - 具有强名称签名项目的批处理构建中的 dotnet build 命令
- android - StreamBuilder 没有从 FireStore 获取数据 | 扑
- django - 在 Django Rest Framework 上获取国外序列化的 ReadOnlyField