Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter 如何打开下拉按钮时,其他小部件被点击,在颤振?_Flutter_Dart - Fatal编程技术网

Flutter 如何打开下拉按钮时,其他小部件被点击,在颤振?

Flutter 如何打开下拉按钮时,其他小部件被点击,在颤振?,flutter,dart,Flutter,Dart,当点击其他小部件时,我需要有一个下拉按钮的选项列表以编程方式打开/显示。我知道这可能不是UI最佳实践,但我需要这种行为: 例如,在下面这样的结构中,我可能需要点击文本(“每个”)打开相邻的下拉按钮的下拉列表,其行为类似于在HTML中单击标签 行(子项:[ 填充物( 填充:仅限常量边集(右:16), child:Text('every'), ), 扩大( 孩子:下拉按钮( 值:_数据['every'], 一旦更改:(字符串val)=>setState(()=>_data['every']=val)

当点击其他小部件时,我需要有一个
下拉按钮
的选项列表以编程方式打开/显示。我知道这可能不是UI最佳实践,但我需要这种行为:

例如,在下面这样的结构中,我可能需要点击
文本(“每个”)
打开相邻的
下拉按钮的下拉列表,其行为类似于在HTML中单击
标签

行(子项:[
填充物(
填充:仅限常量边集(右:16),
child:Text('every'),
),
扩大(
孩子:下拉按钮(
值:_数据['every'],
一旦更改:(字符串val)=>setState(()=>_data['every']=val),
项目:_every_options.map(
(字符串值){
返回下拉菜单项(
价值:价值,
子项:文本(值),
);
},
).toList(),
是的,
),
),
]);
注意:我需要的是这个问题的一般解决方案,而不仅仅是如何使
文本在下面的树中表现得有点“像HTML标签”。它可能需要通过更远处的按钮等来触发打开。

这是设计的API限制之一

不修改SDK,复制dropdown.dart并创建自己的版本,比如自定义dropdown.dart,然后将代码粘贴到那里,这是实现您想要的最简单的方法

在第546行中,将类重命名为CustomDropdownButton,在第660行和第663行中,将_DropdownButtonState重命名为CustomDropdownButtonState,(我们需要将状态类暴露在文件之外)

现在你可以用它做任何你想做的事, 尽管您对_handleTap()感兴趣,但仍然可以打开覆盖菜单选项

与其公开_handleTap()并重构代码,不如添加另一个方法,如:

(line 726)
void callTap() => _handleTap();
现在,将代码更改为使用DropdownButton而不是Flitter的DropdownButton,关键是“设置键”(全局键):p

//一些有状态的小部件实现

  Map<String, String> _data;
  List<String> _every_options;
  // we need the globalKey to access the State.
  final GlobalKey dropdownKey = GlobalKey();

  @override
  void initState() {
    _every_options = List.generate(10, (i) => "item $i");
    _data = {'every': _every_options.first};
    simulateClick();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Row(children: [
        Padding(
          padding: const EdgeInsets.only(right: 16),
          child: Text('every'),
        ),
        Expanded(
          child: CustomDropdownButton<String>(
            key: dropdownKey,
            value: _data['every'],
            onChanged: (String val) => setState(() => _data['every'] = val),
            items: _every_options
                .map((str) => DropdownMenuItem(
                      value: str,
                      child: Text(str),
                    ))
                .toList(),
            isExpanded: true,
          ),
        ),
      ]),
    );
  }

  void simulateClick() {
    Timer(Duration(seconds: 2), () {
      // here's the "magic" to retrieve the state... not very elegant, but works.
      CustomDropdownButtonState state = dropdownKey.currentState;
      state.callTap();
    });
  }
Map\u数据;
列出每个选项;
//我们需要globalKey进入州政府。
最终GlobalKey下拉键=GlobalKey();
@凌驾
void initState(){
_every_options=List.generate(10,(i)=>“item$i”);
_数据={'every':_every_options.first};
模拟单击();
super.initState();
}
@凌驾
小部件构建(构建上下文){
返回安全区(
子对象:行(子对象:[
填充物(
填充:仅限常量边集(右:16),
child:Text('every'),
),
扩大(
孩子:自定义下拉按钮(
键:下拉键,
值:_数据['every'],
一旦更改:(字符串val)=>setState(()=>_data['every']=val),
项目:\u每个\u选项
.map((str)=>下拉菜单项(
值:str,
子:文本(str),
))
.toList(),
是的,
),
),
]),
);
}
void simulateClick(){
计时器(持续时间(秒数:2),(){
//这是恢复状态的“魔法”…不是很优雅,但很有效。
CustomDropdownButtonState状态=dropdownKey.currentState;
state.callTap();
});
}

另一个答案是实现这一点的最佳方法,但正如OP在评论中所要求的,这里有两种非常“黑客”的方法来实现这一点,但没有实现自定义小部件

1。使用
GlobalKey

如果我们查看
DropdownButton
的源代码,我们会注意到它使用
gesturedector
来处理点击。然而,它不是
DropdownButton
的直接后代,我们不能依赖于其他小部件的树结构,因此找到检测器的唯一合理稳定的方法是递归搜索

一个例子值得一千个解释:

class DestropDown扩展了StatefulWidget{
@凌驾
InputDropdownState createState()=>DestropDownState();
}
类DestropDownState扩展状态{
///这是全局键,用于遍历[DropdownButton]的小部件树
GlobalKey _dropdownButtonKey;
void openDropdown(){
手势检测器;
void searchForGestureDetector(BuildContext元素){
元素。visitChildElements((元素){
if(element.widget!=null&&element.widget为GestureDetector){
检测器=element.widget;
返回false;
}否则{
搜索引擎检测器(元件);
}
返回true;
});
}
searchForGestureDetector(\u dropdownButtonKey.currentContext);
断言(检测器!=null);
detector.onTap();
}
@凌驾
小部件构建(构建上下文){
最终下拉菜单=下拉按钮(
键:_dropdownButtonKey,
项目:[
DropdownMenuItem(值:1,子项:文本('1')),
DropdownMenuItem(值:2,子项:文本('2')),
DropdownMenuItem(值:3,子项:文本('3')),
],
onChanged:(int值){},
);
返回列(
mainAxisSize:mainAxisSize.min,
儿童:[
后台(子项:下拉菜单),
FlatButton(按下:打开下拉菜单,子项:文本(“单击我”),
],
);
}
}
2。使用
操作。调用

颤振最近的一个特点是动作(我不确定它的意义,我只是在颤振升级后才注意到它,
DropdownButton
使用它对不同的动作做出反应。。。嗯,行动

因此,触发该按钮的一种稍微不太老套的方法是找到
操作
小部件的上下文并调用必要的操作

有两个