另一个答案是最好的方法,但根据 cmets 中 OP 的要求,这里有两种非常“hacky”的方法来实现这一点,但没有实现自定义小部件。
1.使用GlobalKey直接访问DropdownButton小部件树
如果我们查看DropdownButton 的源代码,我们可以注意到它使用GestureDetector 来处理水龙头。但是,它不是DropdownButton 的直接后代,我们不能依赖其他小部件的树结构,因此找到检测器的唯一合理稳定的方法是递归地进行搜索。
一个例子值得一千次解释:
class DemoDropdown extends StatefulWidget {
@override
InputDropdownState createState() => DemoDropdownState();
}
class DemoDropdownState<T> extends State<DemoDropdown> {
/// This is the global key, which will be used to traverse [DropdownButton]s widget tree
GlobalKey _dropdownButtonKey;
void openDropdown() {
GestureDetector detector;
void searchForGestureDetector(BuildContext element) {
element.visitChildElements((element) {
if (element.widget != null && element.widget is GestureDetector) {
detector = element.widget;
return false;
} else {
searchForGestureDetector(element);
}
return true;
});
}
searchForGestureDetector(_dropdownButtonKey.currentContext);
assert(detector != null);
detector.onTap();
}
@override
Widget build(BuildContext context) {
final dropdown = DropdownButton<int>(
key: _dropdownButtonKey,
items: [
DropdownMenuItem(value: 1, child: Text('1')),
DropdownMenuItem(value: 2, child: Text('2')),
DropdownMenuItem(value: 3, child: Text('3')),
],
onChanged: (int value) {},
);
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(child: dropdown),
FlatButton(onPressed: openDropdown, child: Text('CLICK ME')),
],
);
}
}
2。使用Actions.invoke
Flutter 的最新功能之一是 Actions(我不确定它是什么意思,我今天才在 flutter upgrade 之后才注意到它),DropdownButton 使用它来对不同的.. . 好吧,行动。
因此,触发按钮的一种更简单的方法是找到Actions 小部件的上下文并调用必要的操作。
这种方法有两个优点:首先,Actions 小部件在树中有点高,因此遍历树不会像 GestureDetector 那样长,其次,Actions 似乎是比手势检测更通用的机制,因此它不太可能在未来从 DropdownButton 中消失。
// The rest of the code is the same
void openDropdown() {
_dropdownButtonKey.currentContext.visitChildElements((element) {
if (element.widget != null && element.widget is Semantics) {
element.visitChildElements((element) {
if (element.widget != null && element.widget is Actions) {
element.visitChildElements((element) {
Actions.invoke(element, Intent(ActivateAction.key));
return false;
});
}
});
}
});
}