I’ll like to generate a complex animation in a Canvas, but I’m finding that my CustomPainter.paint method gets called or not when using a Ticker depending on tiny differences.
I have two very similar versions of users of Painter. One created with a widget state, and another within the widget state’s build. I don’t see there should be any different, but one causes paint to be called once, and the other on every tick of the ticker. Why the difference?
Use 1:
class _MyAnimatedWidgetState extends State<MyAnimatedWidget>
with SingleTickerProviderStateMixin {
...
final painter = DemoPainter();
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: painter,
);
}
}
Use 2:
class _MyAnimatedWidgetState extends State<MyAnimatedWidget>
with SingleTickerProviderStateMixin {
...
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: DemoPainter(),
);
}
}
And the full example with a Ticker:
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
class MyAnimatedWidget extends StatefulWidget {
const MyAnimatedWidget({
super.key,
});
@override
State<MyAnimatedWidget> createState() => _MyAnimatedWidgetState();
}
class _MyAnimatedWidgetState extends State<MyAnimatedWidget>
with SingleTickerProviderStateMixin {
late Ticker _ticker;
@override
void initState() {
super.initState();
_ticker = this.createTicker((elapsed) {
print("_MyAnimatedWidgetState.animations tick");
setState(() {
// Yes ... called over and over but paint is not.
print("_MyAnimatedWidgetState.animations setState");
});
});
print("_MyAnimatedWidgetState. START ");
_ticker!.start();
}
@override
void dispose() {
_ticker!.dispose();
super.dispose();
}
// final painter = DemoPainter();
@override
Widget build(BuildContext context) {
print("_MyAnimatedWidgetState.build animations running");
return CustomPaint(
// painter: painter,
painter: DemoPainter(),
);
}
}
class DemoPainter extends CustomPainter {
void paint(Canvas canvas, Size size) { // !!! Called or not called depending Use1/Use2
print("paint");
var center = size / 2;
var paint = Paint()..color = Colors.yellow;
canvas.drawArc(
Rect.fromCenter(
center: Offset(center.width, center.height),
width: 50,
height: 50,
),
0.4,
2 * 3.14 - 0.8,
true,
paint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true; // true/false make not difference to the behavior.
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.red,
child: MyAnimatedWidget(),
)),
);
}
}
void main() {
runApp(MyApp());
}
Using a Linux target.