I am completely newbie in flutter world specially flame-engine. Maybe it's a simple issue. But currently I couldn't figure it out. So please help me!
The main issue is my Draggable component doesn't work all event handler functions seem like doesn't not work correctly. Do you have any idea?
Draggable component code:
import 'package:flame/components.dart';
import 'package:flame/input.dart';
// Zooh bolomjtoi component
class DrawerComponent extends PositionComponent with Draggable {
late final mainRectangle;
Vector2? dragDeltaPosition;
bool get isDragging => dragDeltaPosition != null;
#override
Future<void>? onLoad() async {
final bg = await Sprite.load('drawer.png');
final localSize = Vector2(350, 210);
final mainRectangle = SpriteComponent(size: localSize, sprite: bg);
mainRectangle.position = isDragging ? (dragDeltaPosition)! : Vector2(0, 0);
add(mainRectangle);
}
#override
bool onDragStart(DragStartInfo info) {
print("Drag ehelleee..");
dragDeltaPosition = info.eventPosition.game - position;
return false;
}
#override
bool onDragUpdate(DragUpdateInfo info) {
print("Drag update..");
if (isDragging) {
final localCoords = info.eventPosition.game;
position.setFrom(localCoords - dragDeltaPosition!);
}
return false;
}
#override
bool onDragEnd(DragEndInfo info) {
print("Drag end...");
dragDeltaPosition = null;
return false;
}
#override
bool onDragCancel() {
dragDeltaPosition = null;
return false;
}
}
Main FlameGame class:
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:furniture/drawer.dart';
class Core extends FlameGame with HasDraggables {
late final SpriteComponent mainRectangle;
#override
Future<void>? onLoad() async {
final bg = await Sprite.load('example.jpeg');
final localSize = Vector2(super.size.x * 0.7, super.size.y * 0.6);
final mainRectangle = SpriteComponent(size: localSize, sprite: bg);
mainRectangle.position = Vector2(super.size.x * 0.15, super.size.y * 0.2);
mainRectangle.angle = 0;
add(mainRectangle);
add(DrawerComponent());
}
}
Flutter main class:
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:furniture/core.dart';
void main() {
final game = Core();
runApp(GameWidget(game: game));
}
I think your problem is into your onLoad() because you don't declare the values correctly, I have this example for you:
class Sushi extends SpriteComponent with Draggable, HasGameRef<JapaneseChef>{
/// Sushi constructor
Sushi( this._img, this._position, this._isMove, this._isDraggable,){
position = _position;
size = Vector2(250,250);
}
late final String _img;
late final Vector2 _position;
late Vector2 _dragDeltaPosition;
late final bool _isMove;
late final bool _isDraggable;
/// Get delta position
Vector2 get dragDeltaPosition => _dragDeltaPosition;
set dragDeltaPosition(Vector2? dragDeltaPosition) {
if(dragDeltaPosition != null){
_dragDeltaPosition = dragDeltaPosition;
}
}
#override
Future<void>? onLoad() async{
final spriteSushi = await Sprite.load(_img);
sprite = spriteSushi;
changePriorityWithoutResorting(5);
return super.onLoad();
}
#override
void update(double dt) {
if (_isMove) {
position.x -= 0.6;
if (position.x < -size.x) {
remove(this);
}
}
super.update(dt);
}
#override
bool onDragStart(int pointerId, DragStartInfo info) {
if(_isDraggable) {
dragDeltaPosition = info.eventPosition.game - position;
}
return false;
}
#override
bool onDragCancel(int pointerId) {
dragDeltaPosition = null;
return super.onDragCancel(pointerId);
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo info) {
if (parent is! JapaneseChef) {
return true;
}
final dragDeltaPosition = this.dragDeltaPosition;
position.setFrom(info.eventPosition.game - dragDeltaPosition);
return false;
}
#override
bool onDragEnd(int pointerId, DragEndInfo info) {
dragDeltaPosition = null;
return false;
}
}
Also, you can see the example from Flame engine
Example result
Related
I'm making a e-book application and user can draw lines on the WorkbookDrawingPage Widget by Stack layer.
I want to make the drawn lines saved to the device and books by using shared preference. I tried to use a Json encoding, but couldn't apply to my code.
How to save List<Object> to SharedPreferences in Flutter?
Here's my code
WorkbookViewPage ( PdfViewer and DrawingPage widget)
class WorkbookViewPage extends StatefulWidget {
String downloadedURL;
String workbookName;
WorkbookViewPage(this.downloadedURL, this.workbookName, {super.key});
#override
State<WorkbookViewPage> createState() => _WorkbookViewPageState();
}
class _WorkbookViewPageState extends State<WorkbookViewPage> {
/// Widget Key
GlobalKey _viewKey = GlobalKey();
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
/// Controller
PdfViewerController _pdfViewerController = PdfViewerController();
ScrollController _scrollController = ScrollController();
/// Variables
int _lastClosedPage = 1;
int _currentPage = 1;
bool _memoMode = false;
int drawingPage = 1;
bool isPenTouched = false;
/// pen size control widget Entry
bool isOverlayVisible = false;
OverlayEntry? entry;
/// Hide Overlay Widget
void hideOverlay() {
entry?.remove();
entry = null;
isOverlayVisible = false;
}
/// Count the Total Pages of the Workbook
int _countTotalPages(){
int _totalPages = _pdfViewerController.pageCount;
return _totalPages;
}
/// get Last closed page of workbook
void _loadLastClosedPage() async {
final pagePrefs = await SharedPreferences.getInstance();
_lastClosedPage = pagePrefs.getInt('${widget.workbookName}') ?? 1;
}
#override
void initState() {
super.initState();
// Load Pdf with landScape Mode
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
_pdfViewerController = PdfViewerController();
String workbookName = '${widget.workbookName}';
_loadLastClosedPage();
_countTotalPages();
print("======== Loaded workbook name = ${workbookName} ==========");
}
#override
Widget build(BuildContext context) {
/// Drawing Provider
var p = context.read<DrawingProvider>();
/// set _lastClosedPage
void countLastClosedPage() async {
final pagePrefs = await SharedPreferences.getInstance();
setState(() {
pagePrefs.setInt('${widget.workbookName}', _lastClosedPage);
_lastClosedPage = (pagePrefs.getInt('${widget.workbookName}') ?? 1);
});
}
return Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.white,
elevation: 1,
),
body: Stack(
children: [
InteractiveViewer(
panEnabled: _memoMode ? false : true,
scaleEnabled: _memoMode ? false : true,
maxScale: 3,
child: Stack(
children: [
IgnorePointer(
ignoring: true,
child: SfPdfViewer.network(
widget.downloadedURL,
controller: _pdfViewerController,
key: _pdfViewerKey,
pageLayoutMode: PdfPageLayoutMode.single,
enableDoubleTapZooming: false,
// Save the last closed page number
onPageChanged: (details) {
_lastClosedPage = details.newPageNumber;
_currentPage = details.newPageNumber;
countLastClosedPage();
},
onDocumentLoaded: (details) {
_pdfViewerController.jumpToPage(_lastClosedPage);
_pdfViewerController.zoomLevel = 0;
print("totalpages = ${_countTotalPages().toInt()}");
},
canShowScrollHead: false,
),
),
SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: WorkbookDrawingPage(widget.workbookName, _countTotalPages().toInt(),),
),
],
),
),
WorkbookDawingPage.dart
class WorkbookDrawingPage extends StatefulWidget {
String workbookName;
int countTotalPages;
WorkbookDrawingPage(this.workbookName, this.countTotalPages,{super.key});
#override
State<WorkbookDrawingPage> createState() => _WorkbookDrawingPageState();
}
class _WorkbookDrawingPageState extends State<WorkbookDrawingPage> {
// OverlayEntry widget key
GlobalKey _overlayViewKey = GlobalKey();
Key _viewKey = UniqueKey();
// pen size control widget Entry
bool isOverlayVisible = false;
OverlayEntry? entry;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var p = context.read<DrawingProvider>();
void hideOverlay() {
entry?.remove();
entry = null;
isOverlayVisible = false;
}
return Container(
width: MediaQuery.of(context).size.width * (widget.countTotalPages),
height: MediaQuery.of(context).size.height * 1,
child: CustomPaint(
painter: DrawingPainter(p.lines),
child: Listener(
behavior: HitTestBehavior.translucent,
// Draw lines when stylus hit the screen
onPointerDown: (s) async {
if (s.kind == PointerDeviceKind.stylus) {
setState(() {
p.penMode ? p.penDrawStart(s.localPosition) : null;
p.highlighterMode
? p.highlighterDrawStart(s.localPosition)
: null;
p.eraseMode ? p.erase(s.localPosition) : null;
});
}
/// Stylus with button pressed touched the Screen
else if (s.kind == PointerDeviceKind.stylus ||
s.buttons == kPrimaryStylusButton) {
setState(() {
p.changeEraseModeButtonClicked = true;
});
}
},
onPointerMove: (s) {
if (s.kind == PointerDeviceKind.stylus) {
setState(() {
p.penMode ? p.penDrawing(s.localPosition) : null;
p.highlighterMode
? p.highlighterDrawing(s.localPosition)
: null;
p.eraseMode ? p.erase(s.localPosition) : null;
});
} else if (s.kind == PointerDeviceKind.stylus ||
s.buttons == kPrimaryStylusButton) {
setState(() {
p.changeEraseModeButtonClicked = true;
});
}
},
),
),
);
}
}
The application uses provider for drawing lines and here's provider class
Drawing Provider
Class DrawingProvider extends ChangeNotifier {
/// line List **/
final lines = <List<DotInfo>>[];
Color _selectedColor = Colors.black;
Color get selectedColor => _selectedColor;
/** function method to change Color **/
set changeColor(Color color) {
_selectedColor = color;
notifyListeners();
}
/** Mode Selection **/
bool _penMode = false;
bool get penMode => _penMode;
bool _highlighterMode = false;
bool get highlighterMode => _highlighterMode;
bool _eraseMode = false;
bool get eraseMode => _eraseMode;
bool _memoMode = false;
bool get memoMode => _memoMode;
set changeEraseModeButtonClicked(bool eraseMode) {
eraseMode = true;
_eraseMode = eraseMode;
print("eraseMode가 On ");
notifyListeners();
}
/** 지우개 선택 모드 **/
void changeEraseMode() {
_eraseMode = !_eraseMode;
print("eraseMode is : ${eraseMode}");
_penMode = false;
_highlighterMode = false;
notifyListeners();
}
/** 일반 펜 선택 모드 **/
void changePenMode() {
_penMode = !_penMode;
// _selectedColor = _selectedColor.withOpacity(1);
print("penMode is called : ${penMode} ");
_eraseMode = false;
_highlighterMode = false;
notifyListeners();
}
/** 형광펜 선택 모드 **/
void changeHighlighterMode() {
_highlighterMode = !_highlighterMode;
// _selectedColor = _selectedColor.withOpacity(0.3);
print("Highlighter Mode : ${highlighterMode}");
_eraseMode = false;
_penMode = false;
_opacity = 0.3;
notifyListeners();
}
/** Pen Draw Start **/
void penDrawStart(Offset offset) async {
var oneLine = <DotInfo>[];
oneLine.add(DotInfo(offset, penSize, _selectedColor,));
lines.add(oneLine);
notifyListeners();
}
/** Pen Drawing **/
void penDrawing(Offset offset) {
lines.last.add(DotInfo(offset, penSize, _selectedColor));
notifyListeners();
}
/** highlighter Start **/
void highlighterDrawStart(Offset offset) {
var oneLine = <DotInfo>[];
oneLine
.add(DotInfo(offset, highlighterSize, _selectedColor.withOpacity(0.3),));
lines.add(oneLine);
notifyListeners();
}
/** 터치 후 형광 펜 그리기 **/
void highlighterDrawing(Offset offset) {
lines.last
.add(DotInfo(offset, highlighterSize, _selectedColor.withOpacity(0.3)));
notifyListeners();
}
/** 선 지우기 메서드 **/
void erase(Offset offset) {
final eraseRange = 15;
for (var oneLine in List<List<DotInfo>>.from(lines)) {
for (var oneDot in oneLine) {
if (sqrt(pow((offset.dx - oneDot.offset.dx), 2) +
pow((offset.dy - oneDot.offset.dy), 2)) <
eraseRange) {
lines.remove(oneLine);
break;
}
}
}
notifyListeners();
}
}
and the Dotinfo save the information of the lines
DotInfo.dart
class DotInfo {
final Offset offset;
final double size;
final Color color;
DotInfo(this.offset, this.size, this.color);
}
in the WorkbookDrawingPage.dart , CustomPaint.painter method get DrawingPainter Class
DrawingPainter.dart
class DrawingPainter extends CustomPainter {
final List<List<DotInfo>> lines;
DrawingPainter(this.lines);
#override
void paint(Canvas canvas, Size size) {
for (var oneLine in lines) {
Color? color;
double? size;
var path = Path();
var l = <Offset>[];
for (var oneDot in oneLine) {
color ??= oneDot.color;
size ??= oneDot.size;
l.add(oneDot.offset);
}
path.addPolygon(l, false);
canvas.drawPath(
path,
Paint()
..color = color!
..strokeWidth = size!
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..isAntiAlias = true
..strokeJoin = StrokeJoin.round);
}
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
The Drawing function is related to the provider.
I have no idea how to save the drawn lines into the device. My idea was saving the WorkbookDrawingPage widget itself to the device by using shared preference but, shared preference only can save Int, String, double... so, I tried to encode the DotInfo Class but it cannot be encoded because constructors value is not initialized in the DotInfo Class.
how to save the drawn lines to the device and make them pair with the book?
is saving the widget to the device is possible?? or can you give me any hint or answer?
I want to listen a webp animation's update event on each webp frame, so I create MyImage. but I can't get onUpdateImage trigger, please help. thx
main.dart
AssetImage loadWebp2() {
print('WEBP::loadWebp2');
final image = 'assets/image/07_OK.webp';
var imageProvider = AssetImage(image);
var myImage = MyImage(imageProvider: imageProvider);
myImage.addListener(MyStateListener());
return imageProvider;
}
class MyStateListener extends StateListener {
#override
void onUpdateImage(ImageInfo imageInfo) {
super.onUpdateImage(imageInfo);
print('WEBP::onUpdateImage, $imageInfo');
}
}
MyImage.dart
import 'package:flutter/cupertino.dart';
class MyImage extends StatefulWidget {
const MyImage({
Key key,
#required this.imageProvider,
})
: assert(imageProvider != null),
super(key: key);
final ImageProvider imageProvider;
#override
_MyImageState createState() => _MyImageState();
}
class _MyImageState extends State<MyImage> {
ImageStream _imageStream;
ImageInfo _imageInfo;
StateListener stateListener;
#override
void didChangeDependencies() {
super.didChangeDependencies();
_getImage();
}
#override
void didUpdateWidget(MyImage oldWidget) {
super.didUpdateWidget(oldWidget);
print('WEBP::didUpdateWidget');
if (widget.imageProvider != oldWidget.imageProvider)
_getImage();
}
void _getImage() {
print('WEBP::_getImage');
final ImageStream oldImageStream = _imageStream;
_imageStream =
widget.imageProvider.resolve(createLocalImageConfiguration(context));
if (_imageStream.key != oldImageStream?.key) {
final ImageStreamListener listener = ImageStreamListener(_updateImage);
oldImageStream?.removeListener(listener);
_imageStream.addListener(listener);
}
}
void _updateImage(ImageInfo imageInfo, bool synchronousCall) {
print('WEBP::_updateImage');
setState(() {
// Trigger a build whenever the image changes.
_imageInfo = imageInfo;
if (stateListener != null) {
stateListener.onUpdateImage(_imageInfo);
}
print('WEBP::_updateImage, setState, $imageInfo');
});
}
#override
void dispose() {
_imageStream.removeListener(ImageStreamListener(_updateImage));
super.dispose();
}
#override
Widget build(BuildContext context) {
print('WEBP::build');
return RawImage(
image: _imageInfo?.image, // this is a dart:ui Image object
scale: _imageInfo?.scale ?? 1.0,
);
}
}
class StateListener {
void onUpdateImage(ImageInfo imageInfo) {}
}
I have two sprites in the game e.g Player and Enemy. After collision detection why remove(Component) method is not working?
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/geometry.dart';
import 'package:flutter/material.dart';
void main() async {
runApp(GameWidget(
game: CGame(),
));
}
class CGame extends FlameGame with HasCollidables {
#override
Future<void>? onLoad() async {
add(Enemy());
add(Player());
return super.onLoad();
}
}
class Enemy extends SpriteComponent with HasGameRef, HasHitboxes, Collidable {
Enemy() : super(priority: 1);
#override
Future<void>? onLoad() async {
sprite = await Sprite.load('crate.png');
size = Vector2(100, 100);
position = Vector2(200, gameRef.size.y / 3 * 2);
anchor = Anchor.center;
addHitbox(HitboxRectangle());
return super.onLoad();
}
}
class Player extends SpriteComponent with HasGameRef, HasHitboxes, Collidable {
#override
Future<void>? onLoad() async {
sprite = await Sprite.load('player.png');
size = Vector2(100, 100);
position = Vector2(0, gameRef.size.y / 3 * 2);
anchor = Anchor.center;
addHitbox(HitboxRectangle());
return super.onLoad();
}
#override
void update(double dt) {
position += Vector2(1, 0);
}
#override
void onCollision(Set<Vector2> intersectionPoints, Collidable other) {
if (other is Enemy) {
print('Player hit the Enemy!');
remove(Enemy()); //<== Why this line is not working?
}
}
}
You are trying to remove a new instance of an enemy component, you have to remove the specific one that you collided with, which in this case is other.
You also want to remove other from the game where it is added, if you do remove on the component you are trying to remove a subcomponent.
#override
void onCollision(Set<Vector2> intersectionPoints, Collidable other) {
if (other is Enemy) {
other.removeFromParent();
// It can also be done like this since you have the `HasGameRef` mixin
// gameRef.remove(other);
}
}
}
Successfully implemented a Draggable component. When adding the Hitbox and Collidable mixins to the class extended by PositionComponent the drag functionality stops working.
Is it possible to have a draggable component that is also collidable?
Flutter version: 2.2.3
Flame version: 1.0.0-releasecandidate.13
main.dart
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'DraggablesGame.dart';
void main() {
runApp(
GameWidget(
game: DraggablesGame(),
),
);
}
DraggablesGame.dart
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'DraggableSquare.dart';
class DraggablesGame extends BaseGame with HasDraggableComponents, HasCollidables {
#override
Future<void> onLoad() async {
add(DraggableSquare());
add(DraggableSquare()..y = 350);
}
}
DraggableSquare.dart
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flutter/material.dart' show Colors;
import 'DraggablesGame.dart';
class DraggableSquare extends PositionComponent
with Draggable, HasGameRef<DraggablesGame>, Hitbox, Collidable {
#override
bool debugMode = true;
DraggableSquare({Vector2? position})
: super(
position: position ?? Vector2.all(100),
size: Vector2.all(100),
);
Vector2? dragDeltaPosition;
bool get isDragging => dragDeltaPosition != null;
#override
void update(double dt) {
super.update(dt);
debugColor = isDragging ? Colors.greenAccent : Colors.purple;
}
#override
bool onDragStart(int pointerId, DragStartInfo info) {
dragDeltaPosition = info.eventPosition.game - position;
return false;
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo event) {
final dragDeltaPosition = this.dragDeltaPosition;
if (dragDeltaPosition == null) {
return false;
}
position.setFrom(event.eventPosition.game - dragDeltaPosition);
return false;
}
#override
bool onDragEnd(int pointerId, _) {
dragDeltaPosition = null;
return false;
}
#override
bool onDragCancel(int pointerId) {
dragDeltaPosition = null;
return false;
}
}
Update based on answer
Spydon's answer suggested using addHitbox(HitboxRectangle());. This resulted in the following error:
The method 'addHitbox' isn't defined for the type 'DraggableSquare'.
Instead this modified constructor allows for both the dragging and colliding.
Updated DraggableSquare Constructor
DraggableSquare({Vector2? position})
: super(
position: position,
size: Vector2.all(100),
) {
final hitBox = HitboxRectangle();
addShape(hitBox);
}
When you add the Hitbox mixin you also have to add some hitboxes, otherwise it will not be able to know what it should count as a "hit".
The simplest solution is to add an empty hitbox of either the HitboxRectangle or HitboxCircle type. These hitbox will will the full size of the component if you don't define anything more specific in them.
So to add a HitboxRectangle, you modify your constructor to this:
DraggableSquare({Vector2? position})
: super(
position: position ?? Vector2.all(100),
size: Vector2.all(100),
) {
addShape(HitboxRectangle());
}
If you set debugMode = true you will be able to visually see the hitboxes that you add.
shouldRepaint doesn't repaint when there is a change:
import 'package:flutter/material.dart';
class MainCanvas extends CustomPainter{
static var penPointsToRender = [];
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..color=Colors.black..strokeWidth=4;
renderPenPoints(paint, canvas, 2);
}
static void renderPenPoints(Paint paint, Canvas canvas, double pointsRadius){
for (int i = 0; i < penPointsToRender.length - 1; i++) {
if (penPointsToRender[i + 1] != null && penPointsToRender[i] != null) {
canvas.drawLine(penPointsToRender[i], penPointsToRender[i + 1], paint);
}
}
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
this list get's updated on every touch.
I have this custom gesture detector that uses a provider as it's state management system:
import 'package:flutter/material.dart';
import 'package:flutter_canvas/Widgets/Models/canvas_gesture_detector_model.dart';
class CanvasGestureDetector extends StatefulWidget {
CanvasGestureDetector(this.canvasGestureDetectorModel,{Key key,this.child}) : super(key: key);
CanvasGestureDetectorModel canvasGestureDetectorModel;
Widget child;
#override
_CanvasGestureDetectorState createState() => _CanvasGestureDetectorState();
}
class _CanvasGestureDetectorState extends State<CanvasGestureDetector> {
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanDown: widget.canvasGestureDetectorModel.onPanDown,
onPanUpdate: widget.canvasGestureDetectorModel.onPanUpdate,
onPanEnd: widget.canvasGestureDetectorModel.onPanEnd,
child: widget.child,
);
}
}
the model of the detector is:
import 'package:flutter/material.dart';
import 'package:flutter_canvas/Widgets/Canvas/canvas.dart';
import 'package:flutter_canvas/Widgets/Canvas/canvas_area.dart';
class CanvasGestureDetectorModel with ChangeNotifier{
Function(DragDownDetails) onPanDown;
Function(DragUpdateDetails) onPanUpdate;
Function(DragEndDetails) onPanEnd;
void changeGestureBehavior(BuildContext context,String toolName){
switch(toolName){
case "Brush":
setBrushGestureDetection(context);
break;
}
}
void setBrushGestureDetection(BuildContext context){
onPanDown = (panInfo){
MainCanvas.penPointsToRender.add(panInfo.localPosition);
};
onPanUpdate = (panInfo){
if(
panInfo.globalPosition.dx < CanvasArea.canvasPaddingHorizontal / 2 ||
panInfo.globalPosition.dx > CanvasArea.canvasPaddingHorizontal / 2 + (MediaQuery.of(context).size.width - CanvasArea.canvasPaddingHorizontal) ||
panInfo.globalPosition.dy < CanvasArea.canvasPaddingVertical / 2 - 20 ||
panInfo.globalPosition.dy > (MediaQuery.of(context).size.height - CanvasArea.canvasPaddingVertical) + (CanvasArea.canvasPaddingVertical ) / 2 -20
){return;}
if (MainCanvas.penPointsToRender.elementAt(
MainCanvas.penPointsToRender.length - 1) != panInfo.localPosition) {
MainCanvas.penPointsToRender.add(panInfo.localPosition);
}
};
onPanEnd = (panInfo){
MainCanvas.penPointsToRender.add(null);
};
notifyListeners();
}
}
from some reason,
when I update the number of penPointsToRender it doesn't cause the customPainter to repaint, even though it updates and adds the points to the static list.
I have no idea what causes this, any suggestions would be appreciated