如何在 flutter 中使用 DropdownButton 制作 Tree Select Box

How to make Tree Select Box with DropdownButton in flutter

我想在 Flutter 中制作一个带有 DropDownButton 的 Select 框。 但我无法为它制定完美的算法。 希望得到Flutter高手的大力帮助。 谢谢。

Screenshot of current implementation

我已经自己解决了这个问题。 这是我的代码。 不过希望Flutter高手有更好的解决方案。

  addTaskList(){
taskChildrenList.clear();
print(selectedTaskList.length);
selectedTaskList.forEach((task){
  taskChildrenList.add(Card(
    margin: EdgeInsets.symmetric(vertical: 5),
    child: Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Text("${AppLanguage.selectTaskLabel()} ${task[0].label}",style: TextStyle(fontSize: 15,fontWeight: FontWeight.bold),),
          Flexible(
            child: FittedBox(
              child: DropdownButton<JustificationTask>(
                value: selectedTasks.length==task[0].label-1?null:selectedTasks[task[0].label-1],
                icon: Icon(Icons.chevron_right),
                iconSize: 25,
                elevation: 16,
                style: TextStyle(color: Colors.black),
                underline: Container(height: 1, color: Colors.transparent,),
                onChanged: (JustificationTask value) {
                  setState(() {
                    selectedTaskList.removeRange(value.label, selectedTaskList.length);
                    selectedTasks.removeRange(value.label-1, selectedTasks.length);
                    selectedTasks.add(value);
                    if(value.children.isNotEmpty){
                      selectedTaskList.add(value.children);
                      selectedTask=null;
                    }else{
                      selectedTask=value;
                      equipment=null;
                    }
                  });
                },
                items: task.map<DropdownMenuItem<JustificationTask>>((JustificationTask value) {
                  return DropdownMenuItem<JustificationTask>(
                    value: value,
                    child: SizedBox(width:MediaQuery.of(context).size.width*0.4,child: Text("${taskName(value)}",style: TextStyle(fontSize: 20),)),
                  );
                }).toList(),
                hint: SizedBox(width:MediaQuery.of(context).size.width*0.4,child: Text(AppLanguage.task(),style: TextStyle(fontSize: 20))),
                isExpanded: false,
              ),
            ),
          ),
        ],
      ),
    ),
  ),);
});

}

对于其他 运行 遇到此问题但没有得到此处答案帮助的人...我编写了一个简单的应用程序来完成此操作,select 使用动态下拉菜单从树中选择一个项目纽扣。这是完整的代码:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class Node {
  final String name;
  final List<Node> children;

  Node({this.name, this.children});
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(title: 'Animal Classification'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<String> treeLevels = ['Phylum', 'Class', 'Species'];
  List<Node> selectedNodes = [
    Node(name: 'Animal Kingdom', children: <Node>[
      Node(name: 'Vertebrates', children: <Node>[
        Node(name: 'Fish'),
        Node(name: 'Amphibians'),
        Node(name: 'Reptiles'),
        Node(name: 'Birds'),
        Node(name: 'Mammals', children: <Node>[
          Node(name: 'Bats'),
          Node(name: 'Carnivores'),
          Node(name: 'Birds'),
        ]),
      ]),
      Node(name: 'Annelids'),
      Node(name: 'Molluscs'),
      Node(name: 'Nematodes'),
      Node(name: 'Arthropods', children: <Node>[
        Node(name: 'Crustaceans'),
        Node(name: 'Arachnids'),
        Node(name: 'Insects'),
        Node(name: 'Myriapods'),
      ]),
    ]),
  ];

  @override
  Widget build(BuildContext context) {
    List<Widget> items = [];
    for (var i = 0; i < selectedNodes.length; i++) {
      if (selectedNodes[i] != null &&
          (selectedNodes[i].children?.isNotEmpty ?? false)) {
        items.add(
            Text(treeLevels[i], style: Theme.of(context).textTheme.headline5));

        items.add(DropdownButtonFormField(
          value: selectedNodes.length > i + 1 ? selectedNodes[i + 1] : null,
          items: selectedNodes[i]
              .children
              .map((node) => DropdownMenuItem(
                    value: node,
                    child: Text(node.name),
                  ))
              .toList(),
          onChanged: (selected) => setState(() {
            selectedNodes.removeRange(i + 1, selectedNodes.length);
            selectedNodes.add(selected);
          }),
        ));

        items.add(SizedBox(height: 16.0)); // Padding
      }
    }

    return Scaffold(
        appBar: AppBar(
          title: Center(child: Text(widget.title)),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: ListView(
            children: items,
          ),
        ));
  }
}