Attach badge to node (the node's icon or else on the label)

Issue #31 resolved
Niall Mac Aindriú created an issue

Hello Kevin,

I’ve started to use your flutter treeview package, and it is really good!

I’m using JSON to create the treeview, and I need to show a badge on the node - either on the icon of the node or at the end of the label.

Is it possible to do this?

Míle Buíochas | Many thanks,

Niall.

Comments (13)

  1. Kevin Armstrong

    Hi Niall, it is not possible by default, but a recent update allows you to define your own builder on the TreeView widget. You can then add the badge wherever you like.

  2. Niall Mac Aindriú reporter

    Hi Kevin,

    I’ve switched to the latest version (0.9.0+1), and the NodeIcon is gone (so all of my node icons are now gone). Is there any example anywhere for how to use the new dynamic nodeBuilder function?

    I guess I need to use the nodeBuilder now to recreate my node icons?

    Any chance you could update the main.dart example to show how to use this new functionality in version 0.9.0+1 

    Or even just a code snippet as an example would be great :)

    Míle Buíochas | Many thanks,

    Niall.

  3. Kevin Armstrong

    Niall, apologies for what happened with the icons in the code change. I wanted to get rid of NodeIcon to now support the native tree shaking feature in flutter. Adding icons to your node is as sample is using IconData now. Just pass something like:

    Node(icon: Icons.folder)
    

  4. Niall Mac Aindriú reporter

    Hi Kevin, I’m using JSON to build the tree (see sample below)

    With the latest version (0.9.0+1), the icons are not displayed anymore.

    Do I need to make some changes to the JSON ‘icon’ element?

    Is there a way to add a ‘Badge’ element to the JSON so that the icon has a badge? (see pic below)

    Míle Buíochas | Many thanks,

    Niall.

    pic: tree with badge on icon (also badge displayed after ‘label’

    here’s my JSON …

    [{"id":2,"parentid":1,"label":"Bray","type":"building","key":"2","icon":{"codePoint":59553,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[{"id":3,"parentid":2,"label":"BrayGnd Floor","type":"floor","key":"3","icon":{"codePoint":59553,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[{"id":10,"parentid":3,"label":"BrayRoom1","type":"room","key":"10","icon":{"codePoint":61704,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[{"id":12,"parentid":10,"label":"WorkOrder 0827","type":"workorder","key":"12","icon":{"codePoint":62025,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[]},{"id":13,"parentid":10,"label":"WorkOrder 0828","type":"workorder","key":"13","icon":{"codePoint":62025,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[]}]}]},{"id":4,"parentid":2,"label":"Bray1st Floor","type":"floor","key":"4","icon":{"codePoint":59553,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[]}]},{"id":20,"parentid":1,"label":"Dublin","type":"building","key":"20","icon":{"codePoint":59553,"fontFamily":"fontawesome","fontPackage":null,"color":"grey"},"children":[]}]

  5. Kevin Armstrong

    Use the code below as an example. The class has a reader that can be used to convert your JSON data to Nodes and a builder that displayed a custom node with an indicator.

    class NodeBuilder {
      static reader(List<Map<String, dynamic>> data) {
        return data.map((item) {
          String _key = item['key'];
          String _label = item['label'];
          var _data = item['type'];
          IconData _icon;
          List<Node> _children = [];
          //this is optional because the icon can be dynamically created in the builder
          if (item['icon'] != null) {
            Map<String, dynamic> _iconData = item['icon'];
            _icon = IconData(
              _iconData['codePoint'],
              fontFamily: _iconData['fontFamily'],
              fontPackage: _iconData['fontPackage'],
            );
          }
          if (item['children'] != null) {
            _children = NodeBuilder.reader(List.from(item['children']));
          }
          return Node(
            key: '$_key',
            label: _label,
            icon: _icon,
            data: _data,
            children: _children,
          );
        }).toList();
      }
    
      static builder(BuildContext context, Node node) {
        return ListTile(
          dense: true,
          title: Text(node.label, style: TextStyle(fontSize: 16)),
          contentPadding: EdgeInsets.all(0),
          horizontalTitleGap: 0,
          minVerticalPadding: 0,
          // subtitle: node.data == null ? null : Text(node.data),
          leading: makeIcon(node),
        );
      }
    
      static makeIcon(Node node) {
        IconData _iconData;
        if (node.data == 'building') {
          _iconData = Icons.business;
        } else if (node.data == 'floor') {
          _iconData = Icons.all_inbox_outlined;
        } else if (node.data == 'room') {
          _iconData = Icons.monitor;
        } else if (node.data == 'workorder') {
          _iconData = Icons.insert_drive_file_outlined;
        }
        if (node.key == '2') {
          return _iconWithDot(node, _iconData, Colors.red);
        } else if (node.key == '3') {
          return _iconWithDot(node, _iconData, Colors.red);
        } else if (node.key == '10') {
          return _iconWithDot(node, _iconData, Colors.orange);
        } else if (node.key == '13') {
          return _iconWithDot(node, _iconData, Colors.green);
        }
        return _iconData == null
            ? Icon(Icons.circle, color: Colors.transparent)
            : Icon(_iconData, color: Colors.grey);
      }
    
      static _iconWithDot(Node node, IconData iconData, Color color) {
        return FittedBox(
          child: Stack(
            children: [
              Icon(iconData, color: Colors.grey),
              Positioned(
                right: 0,
                child: Container(
                  width: 10,
                  height: 10,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: color,
                  ),
                ),
              ),
            ],
          ),
        );
      }
    }
    

    I didn’t add the number to the badge but since the indicator is a Container, you can add anything you like.

  6. Niall Mac Aindriú reporter

    Kevin,

    Tá sé thar cionn ar fad! (it’s working great! It’s really, great)

    Céad míle buíochas (hundred, thousand thanks!)

    Niall.

  7. Marina Araujo

    Hello Kevin,

    I’m trying to use this class above to show a checkbox instead of an icon.

    Basically i want to be able to select multiple nodes somehow.

    My problem is that I’m not sure on how to implement it on the nodeBuilder level… follows screenshot of my code:

    If you can help I’d appreciate it. Thanks in advance!

    Best regards,

    Marina

  8. Marina Araujo

    Thanks a lot Kevin!

    Btw, is there any way you of turning the data of the tree into a json string again?

  9. Kevin Armstrong

    On the tree view_controller there is the asMap method. It will return a Map<String, dynamic> object. And toString will return a json string.

    Only thing to note here is that the json returned likely won’t match your original json object. If you look at the asMap method, you can possibly write something similar to export a Map that better matches your original json, especially if you store your object in the data property for each node.

    Hope this helps.

  10. Log in to comment