skip to Main Content

I am working on a Flutter app where I need to generate a tree view from JSON data. The TreeView shown below:

Image shows what my simple tree view should look like

The Table structured as follows:

ParentID ChildID Title
1 0 Root 1
2 0 Root 2
3 1 Node 1.1
4 3 Node 1.1.1
5 3 Node 1.1.2
5 1 Node 1.2
5 2 Node 2.1
5 2 Node 2.2

The JSON data is structured as follows:

[
  {
    "ParentID": 1,
    "ChildID": 0,
    "Title": "Root 1"
  },
  {
    "ParentID": 2,
    "ChildID": 0,
    "Title": "Root 2"
  },
  {
    "ParentID": 3,
    "ChildID": 1,
    "Title": "Node 1.1"
  },
  {
    "ParentID": 4,
    "ChildID": 3,
    "Title": "Node 1.1.1"
  },
  {
    "ParentID": 5,
    "ChildID": 3,
    "Title": "Node 1.1.2"
  },
  {
    "ParentID": 6,
    "ChildID": 1,
    "Title": "Node 1.2"
  },
  {
    "ParentID": 7,
    "ChildID": 2,
    "Title": "Node 2.1"
  },
  {
    "ParentID": 8,
    "ChildID": 2,
    "Title": "Node 2.2"
  }
]

This data represents a hierarchical structure where each node can have multiple children. The ParentID field indicates the parent node, and the ChildID field indicates the current node’s position in the hierarchy.
Currently, I have hardcoded data to generate the tree view, as shown below:

  static const List<MyNode> roots = <MyNode>[
MyNode(
  title: 'Root 1',
  children: <MyNode>[
    MyNode(
      title: 'Node 1.1',
      children: <MyNode>[
        MyNode(title: 'Node 1.1.1'),
        MyNode(title: 'Node 1.1.2'),
      ],
    ),
    MyNode(title: 'Node 1.2'),
  ],
),
MyNode(
  title: 'Root 2',
  children: <MyNode>[
    MyNode(
      title: 'Node 2.1',
    ),
    MyNode(title: 'Node 2.2')
  ],
),];

What I would like to achieve is to dynamically generate this tree view from the JSON data retrieved from a database.
Could someone please help me convert this JSON data into a hierarchical tree view in Flutter? Any guidance or code examples would be greatly appreciated.
Thank you in advance for your help!

2

Answers


  1. I have created tree node widget. Play with your required colors and properties.

    class TreeNodeWidget extends StatelessWidget {
      final MyNode node;
    
      TreeNodeWidget({required this.node});
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0),
          child: ExpansionTile(
            enabled: false,
            initiallyExpanded: true,
            showTrailingIcon: false,
            title: Text(
              node.title,
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            children: node.children
                .map((childNode) => TreeNodeWidget(node: childNode))
                .toList(),
            tilePadding: EdgeInsets.symmetric(horizontal: 16.0),
            childrenPadding: EdgeInsets.only(left: 32.0),
            iconColor: Colors.blue, // Customize the icon color
            collapsedIconColor: Colors.grey, // Customize the collapsed icon color
            backgroundColor: Colors.white, // Customize the background color
            expandedAlignment: Alignment.centerLeft,
            expandedCrossAxisAlignment: CrossAxisAlignment.start,
            textColor: Colors.black, // Customize the text color
            collapsedTextColor: Colors.black54, // Customize collapsed text color
          ),
        );
      }
    }
    

    And your listview as

    ListView(
          children:
              roots.map((rootNode) => TreeNodeWidget(node: rootNode)).toList(),
        )
    

    Hope it helps…

    Login or Signup to reply.
  2. Alright, let’s break this down step by step.

    First, you gonna need to define a model for the nodes in your tree structure. This is pretty straightforward. Here’s how you can do it:

    class MyNode {
      final int parentId;
      final int childId;
      final String title;
      List<MyNode> children;
    
      MyNode({
        required this.parentId,
        required this.childId,
        required this.title,
        this.children = const [],
      });
    }
    

    So, here we’re just saying that each node in the tree has a parentId, a childId, and a title. The children property is a list of MyNode, which means each node can have its own children, making it hierarchical.

    Next, you need to take your JSON data and turn it into a list of these nodes:

    List<MyNode> parseJsonToNodes(List<Map<String, dynamic>> jsonData) {
      return jsonData.map((data) {
        return MyNode(
          parentId: data['ParentID'],
          childId: data['ChildID'],
          title: data['Title'],
        );
      }).toList();
    }
    

    This part is just mapping over your JSON and creating a list of MyNode objects from it. Pretty simple so far.

    But, here’s where it gets a bit tricky. You need to create a hierarchical structure, meaning each node knows who its children are. To do that, you create the tree like this:

    List<MyNode> createTree(List<MyNode> nodes) {
      Map<int, MyNode> nodeMap = {for (var node in nodes) node.childId: node};
    
      List<MyNode> roots = [];
    
      for (var node in nodes) {
        if (node.parentId == 0) {
          roots.add(node);
        } else {
          nodeMap[node.parentId]?.children.add(node);
        }
      }
    
      return roots;
    }
    

    What’s happening here is that you’re first creating a map where each node can be quickly accessed by its childId. Then, you loop through all the nodes. If a node has a parentId of 0, it means it’s a root node, so you add it directly to your roots list. Otherwise, you find its parent in the map and add it as a child to that parent.

    Finally, to display the tree, you use a widget like this:

    class TreeNodeWidget extends StatelessWidget {
      final MyNode node;
    
      TreeNodeWidget({required this.node});
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.symmetric(vertical: 4.0),
          child: ExpansionTile(
            title: Text(node.title),
            children: node.children.map((child) => TreeNodeWidget(node: child)).toList(),
          ),
        );
      }
    }
    

    And remember, always start by defining your entities and models before you dive into handling JSON data. This approach ensures you have a clear understanding of the structure you’re working with, making your implementation much more robust and easier to maintain.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search