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

The little triangle hidden by requirement

Neo4j-OGM 3.2 released

MuleSoft Anypoint Platform can be configured for Single Sign-On (SSO) using Okta, OpenAM or…

7 Popular Use Cases for Apache Kafka

High Availability & Fault Tolerance for Monitoring Stack

An Introduction to AWS SQS Service

Linux Hard Drive Management: For H4ck3r5

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

Brief Summary : Dart Variable

Why should companies prefer Flutter over Native Applications ?

Bringing Life To Your Flutter Application

What are the benefits of Hiring Flutter Developer

What are the benefits of Hiring Flutter Developer