/// Tree view widget library library tree_view; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; class TreeView extends InheritedWidget { final List children; final bool startExpanded; TreeView({ Key key, @required List children, bool startExpanded = false, }) : this.children = children, this.startExpanded = startExpanded, super( key: key, child: _TreeViewData( children: children, ), ); static TreeView of(BuildContext context) { //return context.inheritFromWidgetOfExactType(TreeView); return context.dependOnInheritedWidgetOfExactType(aspect: TreeView); } @override bool updateShouldNotify(TreeView oldWidget) { if (oldWidget.children == this.children && oldWidget.startExpanded == this.startExpanded) { return false; } return true; } } class _TreeViewData extends StatelessWidget { final List children; const _TreeViewData({ this.children, }); @override Widget build(BuildContext context) { return ListView.builder( itemCount: children.length, itemBuilder: (context, index) { return children.elementAt(index); }, ); } } class TreeViewChild extends StatefulWidget { final bool startExpanded; final Widget parent; final List children; final VoidCallback onTap; TreeViewChild({ @required this.parent, @required this.children, this.startExpanded, this.onTap, Key key, }) : super(key: key) { assert(parent != null); assert(children != null); } @override TreeViewChildState createState() => TreeViewChildState(); TreeViewChild copyWith( TreeViewChild source, { bool startExpanded, Widget parent, List children, VoidCallback onTap, }) { return TreeViewChild( parent: parent ?? source.parent, children: children ?? source.children, startExpanded: startExpanded ?? source.startExpanded, onTap: onTap ?? source.onTap, ); } } class TreeViewChildState extends State { bool isExpanded; @override void initState() { super.initState(); isExpanded = widget.startExpanded; } @override void didChangeDependencies() { isExpanded = widget.startExpanded ?? TreeView.of(context).startExpanded; super.didChangeDependencies(); } @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ GestureDetector( child: widget.parent, onTap: widget.onTap ?? () => toggleExpanded(), ), AnimatedContainer( duration: Duration(milliseconds: 400), child: isExpanded ? Column( mainAxisSize: MainAxisSize.min, children: widget.children, ) : Offstage(), ), ], ); } void toggleExpanded() { setState(() { this.isExpanded = !this.isExpanded; }); } }