Things I learned while developing Flutter GraphView widget with MultiChildRenderObject

Why not Custom Painter?

1. We pass our children in the constructor

GraphView({Key key, @required this.graph, @required this.algorithm, EdgeRenderer renderer})
: assert(graph != null),
assert(algorithm != null),
renderer = renderer ?? ArrowEdgeRenderer(),
super(key: key, children: _extractChildren(graph));

2. Laying out: Constraints go down. Sizes go up. Parent sets position

@override
void performLayout() {
if (childCount == 0) {
size = constraints.biggest;
assert(size.isFinite);
return;
}

RenderBox child = firstChild;
int position = 0;
while (child != null) {
final NodeBoxData node = child.parentData as NodeBoxData;

child.layout(BoxConstraints.loose(constraints.biggest), parentUsesSize: true);
graph.getNodeAtPosition(position).size = child.size;

child = node.nextSibling;
position++;
}

size = algorithm.run(graph, 10, 10);

child = firstChild;
position = 0;
while (child != null) {
final NodeBoxData node = child.parentData as NodeBoxData;

node.offset = graph.getNodeAtPosition(position).position;

child = node.nextSibling;
position++;
}
}
Tree Layout in Flutter GraphView

3. MarkNeedsLayout()

@override
RenderCustomLayoutBox createRenderObject(BuildContext context) {
return RenderCustomLayoutBox(graph, algorithm, paint);
}

@override
void updateRenderObject(BuildContext context, RenderCustomLayoutBox renderObject) {
renderObject
..graph = graph
..algorithm = algorithm
..customPaint = paint;
}
Graph get graph => _graph;

set graph(Graph value) {
_graph = value;
markNeedsLayout();
}

4. Ensure that you offset the canvas

@override
void paint(PaintingContext context, Offset offset) {
var paint = Paint()
..color = Colors.black
..strokeWidth = 3
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.butt;

context.canvas.save();
context.canvas.translate(offset.dx, offset.dy);


_renderer.render(context.canvas, graph, paint);

context.canvas.restore();

defaultPaint(context, offset);
}
Force Directed Graph in Flutter GraphView

5. Ensure hitTestChidren() is overridden

@override
bool hitTestChildren(BoxHitTestResult result, {Offset position}) {
return defaultHitTestChildren(result, position: position);
}

Thats All.

  1. RepaintBoundary
  2. Should I use sliver?
  3. Animations inside MultiChildRenderObject

--

--

--

Lead Android Developer, Flutter Lover

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Can we please stop blaming Scrum for bad management?

Blog 11/9–11/15

¿Qué sucede cuando escribes "ls * .c"?

Reverse Proxie’s in Azure

Mutable, Immutable… everything is object!

Mental Model for Developers

Swift Evolution: Unavailability Condition

Developing and Publishing Your Shopify App(Part -1)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Nabil Mosharraf Hossain

Nabil Mosharraf Hossain

Lead Android Developer, Flutter Lover

More from Medium

What's new in Flutter 3?🤩

#FlutterWithSakshi-Part 3

Using Huawei Cloud Functions as Chatbot Service in Flutter ChatBotApp Part-2

Build And Release Artifacts Using GitActions