In SO question How to deal with unwanted widget build asked and answered by Remi Rousselet(author of Provider package), it says using const in front of the class constructor helps avoid unwanted widget builds.
I am having performance issues with my CustomPainter
and CustomClipper
and want to apply this tactic. My CustomClipper
clips a child widget with a certain custom shape and my CustomPainter
paints a shadow according to the clipped shapes boundaries. These two shapes don't change at all. Only mutable object is inside of the child Text
leaf widget. Text
string and length has no effect on the shape of custom clipper and painter.
shouldRepaint
and shouldReclip
are returning false by the way.
Question is how can i make these two classes const or static so that they don't get rebuild with every build by their parent widgets while allowing the Text
widget change its content with the builds? Can you think of anything else to omit unnecessary builds for a widget which does not change at all?
To give more insight as to what I am building: I have several Flutter_Map markers as widgets on the world map. And these markers have a custom clipped shape and a custom shadow to go along with the boundary shape. And inside of this custom shape I have a Marquee
Text
Widget which gets its values from FireStore
.
This Marquee has an animation (like a text ticker moving left and right in order to fit a whole sentence in few pixels width).
The markers Sizes definitely do not change. But I pan the map and their coordinates change in the screen.
single_marker_widget.dart
class SingleMarkerWidget extends StatefulWidget {
final Table table; //filleduchaos this is where I pass the Text widgets string
const SingleMarkerWidget({Key key, this.table}) : super(key: key);
@override
_SingleMarkerWidgetState createState() => _SingleMarkerWidgetState();
}
class _SingleMarkerWidgetState extends State<SingleMarkerWidget> {
@override
Widget build(BuildContext context) {
return ClipShadowPath(
clipper: _SingleMarkerClipper(),
shadow: Shadow(
color: Colors.grey[800],
blurRadius: 25,
offset: Offset(5.0, 8.0),
),
child: RepaintBoundary(
child: Marquee(
textList: [
widget.table.tableGame.gameName,
widget.table.tableVenue.venueName,
widget.table.tableVenue.venueDistrict,
],
),
),
);
}
}
class _SingleMarkerClipper extends CustomClipper<Path> {
@override
getClip(Size size) {
print(
'_SingleMarkerClipper ==== getClip'); //1- THIS PRINT PRINTS WAY TOO OFTEN. THIS IS WHAT I AM TRYING TO GET RID OF.
//....
//DRAW THE CUSTOM SHAPE
//....
return path;
}
@override
bool shouldReclip(CustomClipper oldClipper) {
return false;
}
}
clip_shadow_path.dart
@immutable
class ClipShadowPath extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Path> clipper;
final Widget child;
const ClipShadowPath({
@required this.shadow,
@required this.clipper,
@required this.child,
});
@override
Widget build(BuildContext context) {
print('ClipShadowPath ==== build');
return CustomPaint(
painter: _ClipShadowShadowPainter(
clipper: this.clipper,
shadow: this.shadow,
),
child: ClipPath(child: this.child, clipper: this.clipper),
);
}
}
class _ClipShadowShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Path> clipper;
const _ClipShadowShadowPainter(
{@required this.shadow, @required this.clipper});
@override
void paint(Canvas canvas, Size size) {
print(
'_ClipShadowShadowPainter ==== paint'); //2- THIS PRINT PRINTS WAY TOO OFTEN. THIS IS WHAT I AM TRYING TO GET RID OF.
var paint = shadow.toPaint();
var clipPath = clipper.getClip(size).shift(shadow.offset);
canvas.drawPath(clipPath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}