In Flutter, when creating a CustomPainter, there is an override method, shouldRepaint() that you can return either true or false... presumably to tell the system whether or not to repaint the view.
And in the docs, the description for the method is:
shouldRepaint(covariant CustomPainter oldDelegate) → bool Called whenever a new instance of the custom painter delegate class is provided to the RenderCustomPaint object, or any time that a new CustomPaint object is created with a new instance of the custom painter delegate class (which amounts to the same thing, because the latter is implemented in terms of the former). [...]
I basically don't understand any of that other than the fact that it returns a bool. That makes my head hurt! I also suspect that delving deeper into the definition of "custom painter delegate class," or "RenderCustomPaint object," will not be an enlightening experience.
I'm confused because:
I thought we didn't have to worry about when a widget "should repaint" because Flutter was supposed to decide where and when to re-render the widget tree based on it's own complex optimization decisions.
I thought the paint() method was where you define "this is how this view paints itself, (always and whenever that is necessary)"
All the examples I have found simply return false from this method... but I have noticed different behavior when using true vs false.
If we are always returning false, then how does it ever repaint? (And it does repaint even when false)
If the only possible logic available to us is comparing the "oldDelegate" to (something?) then why are we required to override the method at all?
I haven't seen any example that demonstrates why or how you would return TRUE, and what the logic of such an example would look like in order to make that decision.
Why and how would a knowledgable person decide to return false?
Why and how would a knowledgable person decide to return true?
Can anyone explain it like you're talking to a 13 year old (not Linus Torvalds)?
A simple code example and counter-example would be great (as opposed to an exhaustive explicit explanation!)
I have used CustomPainter extensively, and here is my answer.
Firstly, here is the full doc. You may have only read the starting sentences instead of the full doc. https://api.flutter.dev/flutter/rendering/CustomPainter/shouldRepaint.html
Why and how would a knowledgeable person decide to return false/true?
Here is the rule: If the new instance represents different information than the old instance, then the method should return true, otherwise it should return false.
Example:
class MyPainter extends CustomPainter {
MyPainter() : super();
@override
void paint(Canvas canvas, Size size) => canvas.drawRect(Offset.zero & size, Paint());
// false since all instances of MyPainter contain same information
@override
bool shouldRepaint(MyPainter oldDelegate) => false;
}
class MyPainter extends CustomPainter {
final Color color;
final double width;
MyPainter(this.color, this.width) : super();
@override
void paint(Canvas canvas, Size size) => canvas.drawRect(
Offset.zero & size,
Paint()
..color = color
..strokeWidth = width);
@override
bool shouldRepaint(MyPainter oldDelegate) => oldDelegate.color != this.color || oldDelegate.width != this.width;
}
I thought we didn't have to worry about when a widget "should repaint" because Flutter was supposed to decide where and when to re-render the widget tree based on it's own complex optimization decisions.
Yes and no. This shouldRepaint() is basically an optimization for speed. You can return constantly true if you do not care about performance.
I thought the paint() method was where you define "this is how this view paints itself, (always and whenever that is necessary)"
"this is how this view paints itself" - yes. "always and whenever that is necessary" - partially no. If you provide wrong information to shouldRepaint() you may miss some paints.
All the examples I have found simply return false from this method... but I have noticed different behavior when using true vs false.
What??? I see people returning true, or returning with comparison (see my example below). But when returning false, it can cause problems. Even simply look at comments of this function you will see it should cause problems with constant false. But anyway, if your painter really does not contain any information that can change, it is ok...
If we are always returning false, then how does it ever repaint? (And it does repaint even when false)
/// If the method returns false, then the [paint] call might be optimized
/// away.
///
/// It's possible that the [paint] method will get called even if
/// [shouldRepaint] returns false (e.g. if an ancestor or descendant needed to
/// be repainted). It's also possible that the [paint] method will get called
/// without [shouldRepaint] being called at all (e.g. if the box changes
/// size).
Notice the "might", and the paragraph below. Flutter can choose to paint or not to paint.
If the only possible logic available to us is comparing the "oldDelegate" to (something?) then why are we required to override the method at all?
See my example
I haven't seen any example that demonstrates why or how you would return TRUE, and what the logic of such an example would look like in order to make that decision.
See my example
By the way, it would be great if you gain some insights of Flutter, such as the widget/layout/paint logic etc, then you will easily understand the problem. But anyway I have answered above using words that are hopefully easy to understand even without deep understanding of Flutter.