Reputation: 456
I can't make the custom painter repaint. I tried to use Listenable, callbacks, setState and nothing repaints the screen.
The docs says this:
The most efficient way to trigger a repaint is to either:
- Extend this class and supply a repaint argument to the constructor of the CustomPainter, where that object notifies its listeners when it is time to repaint.
- Extend Listenable (e.g. via ChangeNotifier) and implement CustomPainter, so that the object itself provides the notifications directly. In either case, the CustomPaint widget or RenderCustomPaint render object will listen to the Listenable and repaint whenever the animation ticks, avoiding both the build and layout phases of the pipeline.
But the code don't work as intended.
This is the code I'm using:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(
home: Scaffold(appBar: AppBar(), body: Pad()),
));
}
class Pad extends StatefulWidget {
@override
_PadState createState() => _PadState();
}
class _PadState extends State<Pad> {
@override
Widget build(BuildContext context) {
final painter = Painter();
return GestureDetector(
onTap: () {
setState(() {
painter.addY(10);
});
},
child: CustomPaint(
painter: painter,
child: Container(),
));
}
}
class Painter extends CustomPainter {
double y = 10;
addY(val) {
y += val;
}
@override
void paint(Canvas canvas, Size size) {
canvas.drawCircle(Offset(size.width / 2, y++), 100, Paint());
}
@override
bool shouldRepaint(Painter oldDelegate) {
return true;
}
}
Upvotes: 4
Views: 5294
Reputation: 141
For "Đức Hải Trần" code, just remove SizedBox() and change shouldRepaint return value to 'true', then it works fine.
Upvotes: 0
Reputation: 135
I don't know why but when I add an empty DropdownButtonFormField
widget, It worked.
Even shouldRepaint
function always return false
. The paint
function always re-call when tap to GestureDetector
.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(
home: Scaffold(appBar: AppBar(), body: const Pad()),
));
}
class Pad extends StatefulWidget {
const Pad({Key? key}) : super(key: key);
@override
_PadState createState() => _PadState();
}
class _PadState extends State<Pad> {
@override
Widget build(BuildContext context) {
final painter = Painter();
return Stack(
children: [
SizedBox(
width: 0,
height: 0,
child: DropdownButtonFormField<String>(
onChanged: (value) {}, items: const []),
),
GestureDetector(
onTap: () {
setState(() {
painter.addY(10);
});
},
child: CustomPaint(
painter: Painter(),
child: Container(),
)),
],
);
}
}
class Painter extends CustomPainter {
double y = 10;
addY(val) {
y += val;
}
@override
void paint(Canvas canvas, Size size) {
debugPrint('paint');
canvas.drawCircle(Offset(size.width / 2, y++), 100, Paint());
}
@override
bool shouldRepaint(Painter oldDelegate) {
return false;
}
}
Upvotes: 1
Reputation: 24720
Listenable
works just fine, use ValueNotifier
for example, see https://github.com/pskink/matrix_gesture_detector/blob/master/example/lib/custom_painter_demo.dart for some sample code
Upvotes: 6