How can I paint a Widget on a Canvas in Flutter?
You cannot do this with a CustomPainter.
This class is only a simplification of the real deal: RenderObject, which has access to everything related to painter (and layout+more).
What you should do is, instead of a CustomPainter, create a RenderBox (a 2d RenderObject)
In your case, what you want is to draw a list of widgets. In that situation, you will need to create:
- a MultiChildRenderObjectWidget, a widget that takes a
children
to draw - a RenderBox which mix-in RenderBoxContainerDefaultsMixin, which adds the necessary to RenderBox for handling a list of children.
Wrapping up, a widget used this way:
MyExample(
children: [
Text('foo'),
Text('bar'),
],
),
would be written this way:
import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class MyExample extends MultiChildRenderObjectWidget {
MyExample({
Key? key,
required List<Widget> children,
}) : super(key: key, children: children);
@override
RenderMyExample createRenderObject(BuildContext context) {
return RenderMyExample();
}
}
class MyExampleParentData extends ContainerBoxParentData<RenderBox> {}
class RenderMyExample extends RenderBox
with ContainerRenderObjectMixin<RenderBox, MyExampleParentData> {
@override
void setupParentData(RenderObject child) {
if (child.parentData is! MyExampleParentData) {
child.parentData = MyExampleParentData();
}
}
@override
void performLayout() {
size = constraints.biggest;
for (var child = firstChild; child != null; child = childAfter(child)) {
child.layout(
// limit children to a max height of 50
constraints.copyWith(maxHeight: 50),
);
}
}
@override
void paint(PaintingContext context, Offset offset) {
// Paints all children in order vertically, separated by 50px
var verticalOffset = .0;
for (var child = firstChild; child != null; child = childAfter(child)) {
context.paintChild(child, offset + Offset(0, verticalOffset));
verticalOffset += 50;
}
}
}
Magnus
I have delivered value. But at what cost? Bachelor of Science degree in Computer Engineering. ✪ Started out on ATARI ST BASIC in the 1980's, writing mostly "Look door, take key" type games. ✪ Spent a few years in high school writing various small programs for personal use in Delphi. ✪ Learned PHP/SQL/HTML/JS/CSS and played around with that for a few years. ✪ Did mostly Android and Java for a few years. ✪ Graduated from Sweden Mid University with a BSc in Computer Engineering. At this point, I had learned all there was to know about software development, except where to find that darn "any" key... ✪ Currently working with Flutter/Dart and Delphi (again).
Updated on November 21, 2022Comments
-
Magnus over 1 year
Is there any way to paint a
Widget
at a given position on aCanvas
?More specifically, I want to paint the child widgets of
Marker
's related to aFlutterMap
on a separateCanvas
in front of the actualFlutterMap
widget. Here's an attempt at creating aCustomPainter
that would do that, but I can't figure out how to actually paint the widgets on the canvas. Using theRenderObject
requires aPaintingContext
, which I don't know how to create/retrieve:class MarkerPainter extends CustomPainter { MapController mc; BuildContext context; List<Marker> markers; MarkerPainter(this.context, this.mc, this.markers); @override void paint(Canvas canvas, Size size) { if( markers != null && markers.isNotEmpty ){ for(int i=0; i<markers.length; i++){ Marker marker = markers[i]; Offset o = myCalculateOffsetFromLatLng(marker.point, mc, context); // Won't work, this needs a PaintingContext... marker.builder(context).createElement().renderObject.paint(context, o); } } } @override bool shouldRepaint(MarkerPainter oldDelegate) => oldDelegate.markers != markers; }