Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.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_Recursion_Dart_Dynamic_Tree - Fatal编程技术网

Flutter 颤振中的可扩展列表视图/动态树状视图

Flutter 颤振中的可扩展列表视图/动态树状视图,flutter,recursion,dart,dynamic,tree,Flutter,Recursion,Dart,Dynamic,Tree,我需要一个嵌套的树状视图,其中遍历列表并基于父子关系构建节点。当点击一个节点时,它会展开并用缩进显示其子节点。如果列表很长并且有多个节点且子节点本身有多个子节点,则还可以更改selectedt node.的textstyle颜色和2d滚动。怎么用?请提供帮助。您可以复制粘贴运行下面的完整代码 您可以使用软件包 它有一些您可以自定义的功能,您可以看到下面的工作演示 对于父子关系,您可以在完整代码中看到initState() @override void initState() { _n

我需要一个嵌套的树状视图,其中遍历列表并基于父子关系构建节点。当点击一个节点时,它会展开并用缩进显示其子节点。如果列表很长并且有多个节点且子节点本身有多个子节点,则还可以更改selectedt node.的textstyle颜色和2d滚动。怎么用?请提供帮助。

您可以复制粘贴运行下面的完整代码
您可以使用软件包
它有一些您可以自定义的功能,您可以看到下面的工作演示
对于父子关系,您可以在完整代码中看到
initState()

@override
  void initState() {
    _nodes = [
      Node(
        label: 'documents',
        key: 'docs',
        expanded: docsOpen,
        icon: NodeIcon(
          codePoint:
              docsOpen ? Icons.folder_open.codePoint : Icons.folder.codePoint,
          color: "blue",
        ),
        children: [
          Node(
              label: 'personal',
              key: 'd3',
代码片段

TreeView(
                    controller: _treeViewController,
                    allowParentSelect: _allowParentSelect,
                    supportParentDoubleTap: _supportParentDoubleTap,
                    onExpansionChanged: (key, expanded) =>
                        _expandNode(key, expanded),
                    onNodeTap: (key) {
                      debugPrint('Selected: $key');
                      setState(() {
                        _selectedNode = key;
                        _treeViewController =
                            _treeViewController.copyWith(selectedKey: key);
                      });
                    },
                    theme: _treeViewTheme,
                  )
工作演示

完整代码

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_treeview/tree_view.dart';
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TreeView Example',
      home: MyHomePage(title: 'TreeView Example'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  String _selectedNode;
  List<Node> _nodes;
  TreeViewController _treeViewController;
  bool docsOpen = true;
  final Map<ExpanderPosition, Widget> expansionPositionOptions = const {
    ExpanderPosition.start: Text('Start'),
    ExpanderPosition.end: Text('End'),
  };
  final Map<ExpanderType, Widget> expansionTypeOptions = const {
    ExpanderType.caret: Icon(
      Icons.arrow_drop_down,
      size: 28,
    ),
    ExpanderType.arrow: Icon(Icons.arrow_downward),
    ExpanderType.chevron: Icon(Icons.expand_more),
    ExpanderType.plusMinus: Icon(Icons.add),
  };
  final Map<ExpanderModifier, Widget> expansionModifierOptions = const {
    ExpanderModifier.none: ModContainer(ExpanderModifier.none),
    ExpanderModifier.circleFilled: ModContainer(ExpanderModifier.circleFilled),
    ExpanderModifier.circleOutlined:
        ModContainer(ExpanderModifier.circleOutlined),
    ExpanderModifier.squareFilled: ModContainer(ExpanderModifier.squareFilled),
    ExpanderModifier.squareOutlined:
        ModContainer(ExpanderModifier.squareOutlined),
  };
  ExpanderPosition _expanderPosition = ExpanderPosition.start;
  ExpanderType _expanderType = ExpanderType.caret;
  ExpanderModifier _expanderModifier = ExpanderModifier.none;
  bool _allowParentSelect = false;
  bool _supportParentDoubleTap = false;

  @override
  void initState() {
    _nodes = [
      Node(
        label: 'documents',
        key: 'docs',
        expanded: docsOpen,
        icon: NodeIcon(
          codePoint:
              docsOpen ? Icons.folder_open.codePoint : Icons.folder.codePoint,
          color: "blue",
        ),
        children: [
          Node(
              label: 'personal',
              key: 'd3',
              icon: NodeIcon.fromIconData(Icons.input),
              children: [
                Node(
                    label: 'Resume.docx',
                    key: 'pd1',
                    icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
                Node(
                    label: 'Cover Letter.docx',
                    key: 'pd2',
                    icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
              ]),
          Node(
            label: 'Inspection.docx',
            key: 'd1',
//          icon: NodeIcon.fromIconData(Icons.insert_drive_file),
          ),
          Node(
              label: 'Invoice.docx',
              key: 'd2',
              icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
        ],
      ),
      Node(
          label: 'MeetingReport.xls',
          key: 'mrxls',
          icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
      Node(
          label: 'MeetingReport.pdf',
          key: 'mrpdf',
          icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
      Node(
          label: 'Demo.zip',
          key: 'demo',
          icon: NodeIcon.fromIconData(Icons.archive)),
    ];
    _treeViewController = TreeViewController(
      children: _nodes,
      selectedKey: _selectedNode,
    );
    super.initState();
  }

  ListTile _makeExpanderPosition() {
    return ListTile(
      title: Text('Expander Position'),
      dense: true,
      trailing: CupertinoSlidingSegmentedControl(
        children: expansionPositionOptions,
        groupValue: _expanderPosition,
        onValueChanged: (ExpanderPosition newValue) {
          setState(() {
            _expanderPosition = newValue;
          });
        },
      ),
    );
  }

  SwitchListTile _makeAllowParentSelect() {
    return SwitchListTile.adaptive(
      title: Text('Allow Parent Select'),
      dense: true,
      value: _allowParentSelect,
      onChanged: (v) {
        setState(() {
          _allowParentSelect = v;
        });
      },
    );
  }

  SwitchListTile _makeSupportParentDoubleTap() {
    return SwitchListTile.adaptive(
      title: Text('Support Parent Double Tap'),
      dense: true,
      value: _supportParentDoubleTap,
      onChanged: (v) {
        setState(() {
          _supportParentDoubleTap = v;
        });
      },
    );
  }

  ListTile _makeExpanderType() {
    return ListTile(
      title: Text('Expander Style'),
      dense: true,
      trailing: CupertinoSlidingSegmentedControl(
        children: expansionTypeOptions,
        groupValue: _expanderType,
        onValueChanged: (ExpanderType newValue) {
          setState(() {
            _expanderType = newValue;
          });
        },
      ),
    );
  }

  ListTile _makeExpanderModifier() {
    return ListTile(
      title: Text('Expander Modifier'),
      dense: true,
      trailing: CupertinoSlidingSegmentedControl(
        children: expansionModifierOptions,
        groupValue: _expanderModifier,
        onValueChanged: (ExpanderModifier newValue) {
          setState(() {
            _expanderModifier = newValue;
          });
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    TreeViewTheme _treeViewTheme = TreeViewTheme(
      expanderTheme: ExpanderThemeData(
        type: _expanderType,
        modifier: _expanderModifier,
        position: _expanderPosition,
        color: Colors.grey.shade800,
        size: 20,
      ),
      labelStyle: TextStyle(
        fontSize: 16,
        letterSpacing: 0.3,
      ),
      parentLabelStyle: TextStyle(
        fontSize: 16,
        letterSpacing: 0.1,
        fontWeight: FontWeight.w800,
        color: Colors.blue.shade700,
      ),
      iconTheme: IconThemeData(
        size: 18,
        color: Colors.grey.shade800,
      ),
      colorScheme: Theme.of(context).brightness == Brightness.light
          ? ColorScheme.light(
              primary: Colors.blue.shade50,
              onPrimary: Colors.grey.shade900,
              background: Colors.transparent,
              onBackground: Colors.black,
            )
          : ColorScheme.dark(
              primary: Colors.black26,
              onPrimary: Colors.white,
              background: Colors.transparent,
              onBackground: Colors.white70,
            ),
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        elevation: 0,
      ),
      body: GestureDetector(
        onTap: () {
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Container(
          color: Colors.grey.shade200,
          padding: EdgeInsets.all(20),
          height: double.infinity,
          child: Column(
            children: <Widget>[
              Container(
                height: 300,
                child: Column(
                  children: <Widget>[
                    _makeExpanderPosition(),
                    _makeExpanderType(),
                    _makeExpanderModifier(),
                    _makeAllowParentSelect(),
                    _makeSupportParentDoubleTap(),
                  ],
                ),
              ),
              Expanded(
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(10),
                  ),
                  padding: EdgeInsets.all(10),
                  child: TreeView(
                    controller: _treeViewController,
                    allowParentSelect: _allowParentSelect,
                    supportParentDoubleTap: _supportParentDoubleTap,
                    onExpansionChanged: (key, expanded) =>
                        _expandNode(key, expanded),
                    onNodeTap: (key) {
                      debugPrint('Selected: $key');
                      setState(() {
                        _selectedNode = key;
                        _treeViewController =
                            _treeViewController.copyWith(selectedKey: key);
                      });
                    },
                    theme: _treeViewTheme,
                  ),
                ),
              ),
              GestureDetector(
                onTap: () {
                  debugPrint('Close Keyboard');
                  FocusScope.of(context).unfocus();
                },
                child: Container(
                  padding: EdgeInsets.only(top: 20),
                  alignment: Alignment.center,
                  child: Text(_treeViewController.getNode(_selectedNode) == null
                      ? ''
                      : _treeViewController.getNode(_selectedNode).label),
                ),
              )
            ],
          ),
        ),
      ),
      bottomNavigationBar: SafeArea(
        top: false,
        child: ButtonBar(
          alignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            CupertinoButton(
              child: Text('Node'),
              onPressed: () {
                setState(() {
                  _treeViewController = _treeViewController.copyWith(
                    children: _nodes,
                  );
                });
              },
            ),
            CupertinoButton(
              child: Text('JSON'),
              onPressed: () {
                setState(() {
                  _treeViewController =
                      _treeViewController.loadJSON(json: US_STATES_JSON);
                });
              },
            ),
            CupertinoButton(
              child: Text('Toggle'),
              onPressed: _treeViewController.selectedNode != null &&
                      _treeViewController.selectedNode.isParent
                  ? () {
                      setState(() {
                        _treeViewController = _treeViewController
                            .withToggleNode(_treeViewController.selectedKey);
                      });
                    }
                  : null,
            ),
            CupertinoButton(
              child: Text('Edit'),
              onPressed: () {
                TextEditingController editingController = TextEditingController(
                    text: _treeViewController.selectedNode.label);
                showCupertinoDialog(
                    context: context,
                    builder: (context) {
                      return CupertinoAlertDialog(
                        title: Text('Edit Label'),
                        content: Container(
                          height: 80,
                          alignment: Alignment.center,
                          padding: EdgeInsets.all(10),
                          child: CupertinoTextField(
                            controller: editingController,
                            autofocus: true,
                          ),
                        ),
                        actions: <Widget>[
                          CupertinoDialogAction(
                            child: Text('Cancel'),
                            isDestructiveAction: true,
                            onPressed: () => Navigator.of(context).pop(),
                          ),
                          CupertinoDialogAction(
                            child: Text('Update'),
                            isDefaultAction: true,
                            onPressed: () {
                              if (editingController.text.isNotEmpty) {
                                setState(() {
                                  Node _node = _treeViewController.selectedNode;
                                  _treeViewController =
                                      _treeViewController.withUpdateNode(
                                          _treeViewController.selectedKey,
                                          _node.copyWith(
                                              label: editingController.text));
                                });
                                debugPrint(editingController.text);
                              }
                              Navigator.of(context).pop();
                            },
                          ),
                        ],
                      );
                    });
              },
            ),
          ],
        ),
      ),
    );
  }

  _expandNode(String key, bool expanded) {
    String msg = '${expanded ? "Expanded" : "Collapsed"}: $key';
    debugPrint(msg);
    Node node = _treeViewController.getNode(key);
    if (node != null) {
      List<Node> updated;
      if (key == 'docs') {
        updated = _treeViewController.updateNode(
          key,
          node.copyWith(
              expanded: expanded,
              icon: NodeIcon(
                codePoint: expanded
                    ? Icons.folder_open.codePoint
                    : Icons.folder.codePoint,
                color: expanded ? "blue600" : "grey700",
              )),
        );
      } else {
        updated = _treeViewController.updateNode(
            key, node.copyWith(expanded: expanded));
      }
      setState(() {
        if (key == 'docs') docsOpen = expanded;
        _treeViewController = _treeViewController.copyWith(children: updated);
      });
    }
  }
}

class ModContainer extends StatelessWidget {
  final ExpanderModifier modifier;

  const ModContainer(this.modifier, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    double _borderWidth = 0;
    BoxShape _shapeBorder = BoxShape.rectangle;
    Color _backColor = Colors.transparent;
    Color _backAltColor = Colors.grey.shade700;
    switch (modifier) {
      case ExpanderModifier.none:
        break;
      case ExpanderModifier.circleFilled:
        _shapeBorder = BoxShape.circle;
        _backColor = _backAltColor;
        break;
      case ExpanderModifier.circleOutlined:
        _borderWidth = 1;
        _shapeBorder = BoxShape.circle;
        break;
      case ExpanderModifier.squareFilled:
        _backColor = _backAltColor;
        break;
      case ExpanderModifier.squareOutlined:
        _borderWidth = 1;
        break;
    }
    return Container(
      decoration: BoxDecoration(
        shape: _shapeBorder,
        border: _borderWidth == 0
            ? null
            : Border.all(
                width: _borderWidth,
                color: _backAltColor,
              ),
        color: _backColor,
      ),
      width: 15,
      height: 15,
    );
  }
}

const List<Map<String, dynamic>> US_STATES = [
  {
    "label": "A",
    "children": [
      {"label": "Alabama", "key": "AL"},
      {"label": "Alaska", "key": "AK"},
      {"label": "American Samoa", "key": "AS"},
      {"label": "Arizona", "key": "AZ"},
      {"label": "Arkansas", "key": "AR"}
    ]
  },
  {
    "label": "C",
    "children": [
      {"label": "California", "key": "CA"},
      {"label": "Colorado", "key": "CO"},
      {"label": "Connecticut", "key": "CT"},
    ]
  },
  {
    "label": "D",
    "children": [
      {"label": "Delaware", "key": "DE"},
      {"label": "District Of Columbia", "key": "DC"},
    ]
  },
  {
    "label": "F",
    "children": [
      {"label": "Federated States Of Micronesia", "key": "FM"},
      {"label": "Florida", "key": "FL"},
    ]
  },
  {
    "label": "G",
    "children": [
      {"label": "Georgia", "key": "GA"},
      {"label": "Guam", "key": "GU"},
    ]
  },
  {
    "label": "H",
    "children": [
      {"label": "Hawaii", "key": "HI"},
    ]
  },
  {
    "label": "I",
    "children": [
      {"label": "Idaho", "key": "ID"},
      {"label": "Illinois", "key": "IL"},
      {"label": "Indiana", "key": "IN"},
      {"label": "Iowa", "key": "IA"},
    ]
  },
  {
    "label": "K",
    "children": [
      {"label": "Kansas", "key": "KS"},
      {"label": "Kentucky", "key": "KY"},
    ]
  },
  {
    "label": "L",
    "children": [
      {"label": "Louisiana", "key": "LA"},
    ]
  },
  {
    "label": "M",
    "children": [
      {"label": "Maine", "key": "ME"},
      {"label": "Marshall Islands", "key": "MH"},
      {"label": "Maryland", "key": "MD"},
      {"label": "Massachusetts", "key": "MA"},
      {"label": "Michigan", "key": "MI"},
      {"label": "Minnesota", "key": "MN"},
      {"label": "Mississippi", "key": "MS"},
      {"label": "Missouri", "key": "MO"},
      {"label": "Montana", "key": "MT"},
    ]
  },
  {
    "label": "N",
    "children": [
      {"label": "Nebraska", "key": "NE"},
      {"label": "Nevada", "key": "NV"},
      {"label": "New Hampshire", "key": "NH"},
      {"label": "New Jersey", "key": "NJ"},
      {"label": "New Mexico", "key": "NM"},
      {"label": "New York", "key": "NY"},
      {"label": "North Carolina", "key": "NC"},
      {"label": "North Dakota", "key": "ND"},
      {"label": "Northern Mariana Islands", "key": "MP"},
    ]
  },
  {
    "label": "O",
    "children": [
      {"label": "Ohio", "key": "OH"},
      {"label": "Oklahoma", "key": "OK"},
      {"label": "Oregon", "key": "OR"},
    ]
  },
  {
    "label": "P",
    "children": [
      {"label": "Palau", "key": "PW"},
      {"label": "Pennsylvania", "key": "PA"},
      {"label": "Puerto Rico", "key": "PR"},
    ]
  },
  {
    "label": "R",
    "children": [
      {"label": "Rhode Island", "key": "RI"},
    ]
  },
  {
    "label": "S",
    "children": [
      {"label": "South Carolina", "key": "SC"},
      {"label": "South Dakota", "key": "SD"},
    ]
  },
  {
    "label": "T",
    "children": [
      {"label": "Tennessee", "key": "TN"},
      {"label": "Texas", "key": "TX"},
    ]
  },
  {
    "label": "U",
    "children": [
      {"label": "Utah", "key": "UT"},
    ]
  },
  {
    "label": "V",
    "children": [
      {"label": "Vermont", "key": "VT"},
      {"label": "Virgin Islands", "key": "VI"},
      {"label": "Virginia", "key": "VA"},
    ]
  },
  {
    "label": "W",
    "children": [
      {"label": "Washington", "key": "WA"},
      {"label": "West Virginia", "key": "WV"},
      {"label": "Wisconsin", "key": "WI"},
      {"label": "Wyoming", "key": "WY"}
    ]
  },
];

String US_STATES_JSON = jsonEncode(US_STATES);
import'包装:flift/cupertino.dart';
进口“包装:颤振/材料.省道”;
导入“package:flatter_treeview/tree_view.dart”;
导入“dart:convert”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
//此小部件是应用程序的根。
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“TreeView示例”,
主页:MyHomePage(标题:“TreeView示例”),
);
}
}
类MyHomePage扩展StatefulWidget{
MyHomePage({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_MyHomePageState createState()=>\u MyHomePageState();
}
类_MyHomePageState扩展状态{
字符串_selectedNode;
列表节点;
TreeView控制器\u TreeView控制器;
bool docsOpen=真;
最终地图扩展位置选项=常量{
ExpanderPosition.start:Text('start'),
ExpanderPosition.end:文本('end'),
};
最终映射扩展类型选项=常量{
ExpanderType.caret:图标(
Icons.arrow\u下拉菜单,
尺码:28,
),
ExpanderType.arrow:图标(图标。向下箭头),
ExpanderType.chevron:Icon(Icons.expand_more),
ExpanderType.plusMinus:Icon(Icons.add),
};
最终映射扩展ModifierOptions=const{
ExpanderModifier.none:ModContainer(ExpanderModifier.none),
ExpanderModifier.circleFilled:ModContainer(ExpanderModifier.circleFilled),
ExpanderModifier.circleOutlined:
ModContainer(ExpanderModifier.圆圈),
ExpanderModifier.squareFilled:ModContainer(ExpanderModifier.squareFilled),
ExpanderModifier.xml文件:
ModContainer(ExpanderModifier.square),
};
ExpanderPosition\u ExpanderPosition=ExpanderPosition.start;
ExpanderType _ExpanderType=ExpanderType.caret;
ExpanderModifier\u ExpanderModifier=ExpanderModifier.none;
bool _allowParentSelect=false;
bool\u supportParentDoubleTap=false;
@凌驾
void initState(){
_节点=[
节点(
标签:“文件”,
关键字:“文档”,
扩展:docsOpen,
图标:NodeIcon(
代码点:
docsOpen?Icons.folder_open.codePoint:Icons.folder.codePoint,
颜色:“蓝色”,
),
儿童:[
节点(
标签:'个人',
键:“d3”,
图标:NodeIcon.fromIconda(Icons.input),
儿童:[
节点(
标签:“Resume.docx”,
键:“pd1”,
图标:NodeIcon.fromIconda(Icons.insert\u drive\u file)),
节点(
标签:“求职信.docx”,
键:“pd2”,
图标:NodeIcon.fromIconda(Icons.insert\u drive\u file)),
]),
节点(
标签:“Inspection.docx”,
键:“d1”,
//图标:NodeIcon.fromIconda(图标.插入驱动器文件),
),
节点(
标签:“Invoice.docx”,
键:“d2”,
图标:NodeIcon.fromIconda(Icons.insert\u drive\u file)),
],
),
节点(
标签:“MeetingReport.xls”,
关键字:“mrxls”,
图标:NodeIcon.fromIconda(Icons.insert\u drive\u file)),
节点(
标签:“MeetingReport.pdf”,
关键字:“mrpdf”,
图标:NodeIcon.fromIconda(Icons.insert\u drive\u file)),
节点(
标签:“Demo.zip”,
键:“演示”,
图标:NodeIcon.fromiconda(Icons.archive)),
];
_TreeView控制器=TreeView控制器(
子节点:_节点,
selectedKey:\u selectedNode,
);
super.initState();
}
ListTile_makeExpanderPosition(){
返回列表块(
标题:文本(“扩展器位置”),
是的,
尾部:CupertinoSlidingSegmentedControl(
子项:扩展位置选项,
groupValue:_expanderPosition,
onValueChanged:(ExpanderPosition newValue){
设置状态(){
_expanderPosition=newValue;
});
},
),
);
}
SwitchListTile_makeAllowParentSelect(){
返回SwitchListTile.adaptive(
标题:文本(“允许父选择”),
是的,
值:_allowParentSelect,
一旦更改:(v){
设置状态(){
_allowParentSelect=v;
});
},
);
}
SwitchListTile_makeSupportParentDoubleTap(){
返回SwitchListTile.adaptive(
标题:文本(“支持父双击”),
是的,
值:_supportParentDoubleTap,
一旦更改:(v){
设置状态(){
_supportParentDoubleTap=v;
});
},
);
}
ListTile_makeExpanderType(){
返回列表块(
标题:文本(“扩展样式”),
是的,
尾部:CupertinoSlidingSegmentedControl(
子项:expansionTypeOptions,
groupValue:\u expanderType,
onValueChanged:(ExpanderType newValue){
设置状态(){
_expanderType=newValue;
});
},
),
);
}
ListTile_makeExpanderModifier(){
返回列表块(
标题:文本(“扩展修饰符”),
是的,
尾部:CupertinoSlidingSegmentedControl(
子项:扩展修改器选项,
groupValue:\u expanderModifier,
onValueChanged:(扩展器)