I’ve been searching around the answer and didn’t find much information about how to use Riverpod with CustomPainter.
I got two problems that showed up when I used Riverpod with CustomPainter.
-
(Fixed, please ignore.) I tried to use CustomPainter to draw lines, but CustomPainter won’t draw the line after the start point and the end point has changed. (ref.watch not updating immediately)
-
There is a provider I need to update inside CustomPainter, which gave me an error like this: “Modifying a provider inside those life-cycles is not allowed, as it could lead to an inconsistent UI state.” (I know I shouldn’t update the value inside the build, but I’m curious about how to solve this, especially for CustomPainter or CustomMultiChildLayout.)
Consumer(
builder: (BuildContext context, WidgetRef ref, Widget? child) {
return CustomPaint(
painter: EdgePainter(
ref: ref,
),
);
},
),
class EdgePainter extends CustomPainter {
WidgetRef ref;
EdgePainter({
required this.ref,
});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..color = Colors.blue;
var node = ref.watch(connectedNodeListProvider);
var start = ref.watch(startKeyProvider);
var end = ref.watch(endKeyProvider);
var cardPositions = ref.watch(cardPositionMapProvider);
if (node.isNotEmpty) {
for (var i in node) {
if (cardPositions[i.$1] != Offset.infinite &&
cardPositions[i.$2] != Offset.infinite) {
canvas.drawLine(cardPositions[i.$1]!, cardPositions[i.$2]!, paint);
}
}
}
if (start != null && end != null) {
if (cardPositions[start] != Offset.infinite &&
cardPositions[end] != Offset.infinite) {
canvas.drawLine(cardPositions[start]!, cardPositions[end]!, paint);
node.add((start!, end!));
// var nodeValue = ref.read(connectedNodeListProvider);
// nodeValue.add((start, end));
// ref.read(connectedNodeListProvider.notifier).update((state) {
// state = nodeValue.toList();
// return state;
// });
start = null;
end = null;
}
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
I’m new to Riverpod, so please tell me anything I did wrong here.
You should only use ref.watch
inside a widget build
method, consumer builder
method, or the body of another provider. Move all ref.watch
to the Consumer
‘s builder
body and pass the values as arguments to EdgePainter
:
Consumer(
builder: (BuildContext context, WidgetRef ref, Widget? child) {
var node = ref.watch(connectedNodeListProvider);
var start = ref.watch(startKeyProvider);
var end = ref.watch(endKeyProvider);
var cardPositions = ref.watch(cardPositionMapProvider);
return CustomPaint(
painter: EdgePainter(
ref: ref,
node: node,
start: start,
end: end,
cardPositions: cardPositions,
),
);
},
),
Make shouldRepaint
returns true
if there are changes from those parameters that should trigger the paint
method.
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => start != oldDelegate.start && ... // This is just an example