Skip to content

Instantly share code, notes, and snippets.

@imaNNeo
Created August 12, 2021 19:52
Show Gist options
  • Save imaNNeo/3165e0caf30ca220a239dea0ace320e7 to your computer and use it in GitHub Desktop.
Save imaNNeo/3165e0caf30ca220a239dea0ace320e7 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
brightness: Brightness.dark,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1B2339),
body: Row(
children: [
Container(
width: 300,
color: Colors.white.withOpacity(0.03),
child: TreeView(
nodes: [
TreeNode(
builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'scatterSpots',
indent,
isLeaf,
isExpanded,
);
},
childNodes: [
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'Spot 1',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'Spot 2',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'Spot 3',
indent,
isLeaf,
isExpanded,
);
}),
],
),
TreeNode(
builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'titlesData',
indent,
isLeaf,
isExpanded,
);
},
childNodes: [
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'show: true',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(
builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'leftTitles',
indent,
isLeaf,
isExpanded,
);
},
childNodes: [
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'showTitles: true',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'reservedSize: 40',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'margin: 8',
indent,
isLeaf,
isExpanded,
);
}),
]),
TreeNode(
builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'topTitles',
indent,
isLeaf,
isExpanded,
);
},
childNodes: [
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'showTitles: true',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'reservedSize: 40',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'margin: 8',
indent,
isLeaf,
isExpanded,
);
}),
],
),
TreeNode(
builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'rightTitles',
indent,
isLeaf,
isExpanded,
);
},
childNodes: [
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'showTitles: true',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'reservedSize: 40',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'margin: 8',
indent,
isLeaf,
isExpanded,
);
}),
],
),
TreeNode(
builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'bottomTitles',
indent,
isLeaf,
isExpanded,
);
},
childNodes: [
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'showTitles: true',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'reservedSize: 40',
indent,
isLeaf,
isExpanded,
);
}),
TreeNode(builder: (context, indent, isExpanded, isLeaf) {
return TreeItemWidget(
'margin: 8',
indent,
isLeaf,
isExpanded,
);
}),
],
),
],
)
],
),
)
],
),
);
}
}
class TreeView extends StatefulWidget {
final List<TreeNode> nodes;
TreeView({
Key? key,
required this.nodes,
}) : super(key: key);
@override
_TreeViewState createState() => _TreeViewState();
}
class _TreeViewState extends State<TreeView> {
late List<_InternalTreeNode> _internalNodes;
@override
void initState() {
_internalNodes = widget.nodes.toInternalNodes();
super.initState();
}
@override
Widget build(BuildContext context) {
return ListView(
children: toWidgets(_internalNodes, 0),
);
}
List<Widget> toWidgets(List<_InternalTreeNode> internalNodes, int indent) {
return internalNodes.asMap().entries.map((entry) {
final node = entry.value;
final index = entry.key;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
InkWell(
onTap: () {
setState(() {
node.isExpanded = !node.isExpanded;
});
},
child: node.builder(context, indent, node.isExpanded, node.isLeaf),
)
] +
[if (node.isExpanded) ...toWidgets(node.childNodes, indent + 1)],
);
}).toList();
}
}
extension on List<TreeNode> {
List<_InternalTreeNode> toInternalNodes() {
return map((node) => _InternalTreeNode(node, true, node.childNodes.toInternalNodes())).toList();
}
}
class TreeNode {
final TreeWidgetBuilder builder;
final List<TreeNode> childNodes;
TreeNode({required this.builder, this.childNodes = const []});
bool get isLeaf => childNodes.isEmpty;
}
class _InternalTreeNode {
final TreeNode node;
final List<_InternalTreeNode> childNodes;
bool isExpanded;
_InternalTreeNode(this.node, this.isExpanded, this.childNodes);
TreeWidgetBuilder get builder => node.builder;
bool get isLeaf => node.isLeaf;
}
typedef TreeWidgetBuilder = Widget Function(BuildContext context, int indent, bool isExpanded, bool isLeaf);
class TreeItemWidget extends StatelessWidget {
final String text;
final int indent;
final bool isLeaf;
final bool isExpanded;
final double indentSpace;
final double iconSize;
final double iconHorizontalPadding;
const TreeItemWidget(
this.text,
this.indent,
this.isLeaf,
this.isExpanded, {
this.indentSpace = 28,
this.iconSize = 18,
this.iconHorizontalPadding = 8,
}) : super();
@override
Widget build(BuildContext context) {
return Container(
height: 44,
padding: EdgeInsets.only(left: 6 + iconHorizontalPadding + (indent * indentSpace)),
child: Align(
child: Row(
children: [
if (!isLeaf) ...[
Icon(isExpanded ? Icons.keyboard_arrow_down : Icons.chevron_right, size: iconSize),
SizedBox(width: iconHorizontalPadding),
],
Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
)
],
),
alignment: Alignment.centerLeft,
),
);
}
}
@imaNNeo
Copy link
Author

imaNNeo commented Aug 13, 2021

ezgif.com-gif-maker.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment