I have created a Canvas
using Flutter
where we can draw lines using different brush sizes. There are three brushes with different sizes to set the thickness of the lines. However, changing the brush size affects the size of all previously drawn lines.
I would like to know how to prevent the thickness of previously drawn lines from changing when changing the brush size. Any suggestions or help would be appreciated.
Here is my code:
main.dart:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Canvas',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const CanvasPage(),
);
}
}
class CanvasPage extends StatefulWidget {
const CanvasPage({super.key});
@override
CanvasPageState createState() => CanvasPageState();
}
class CanvasPageState extends State<CanvasPage> {
List<Offset> _points = <Offset>[];
double _pointSize = 5.0;
void _handlePointerDown(PointerEvent event) {
setState(() {
_points = List.from(_points)..add(event.localPosition);
});
}
void _handlePointerMove(PointerEvent event) {
setState(() {
_points = List.from(_points)..add(event.localPosition);
});
}
void _handlePointerUp(PointerEvent event) {
setState(() {
_points = List.from(_points)..add(event.localPosition);
});
}
void _changePointSize(double value) {
setState(() {
_pointSize = value;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Canvas'),
),
body: Listener(
onPointerDown: _handlePointerDown,
onPointerMove: _handlePointerMove,
onPointerUp: _handlePointerUp,
child: CustomPaint(
painter: CanvasPainter(_points, _pointSize),
size: Size.infinite,
),
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
_changePointSize(5.0);
},
),
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
_changePointSize(10.0);
},
),
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
_changePointSize(15.0);
},
),
],
),
),
);
}
}
class CanvasPainter extends CustomPainter {
List<Offset> points;
double pointSize;
CanvasPainter(this.points, this.pointSize);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.blue
..strokeCap = StrokeCap.round
..strokeWidth = pointSize;
for (int i = 0; i < points.length - 1; i++) {
canvas.drawLine(points[i], points[i + 1], paint);
}
}
@override
bool shouldRepaint(CanvasPainter oldDelegate) => true;
}
Once you change the pointSize:
void _changePointSize(double value) {
setState(() {
_pointSize = value;
});
}
Your rebuilding the whole Custom Painter. I would suggest you try this(not sure it will work but):
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Canvas',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const CanvasPage(),
);
}
}
class CanvasPage extends StatefulWidget {
const CanvasPage({Key? key});
@override
CanvasPageState createState() => CanvasPageState();
}
class CanvasPageState extends State<CanvasPage> {
List<dynamic> _points = <dynamic>[];
double _pointSize = 5.0;
void _handlePointerDown(PointerEvent event) {
setState(() {
_points = List.from(_points)..add([event.localPosition,_pointSize]);
});
}
void _handlePointerMove(PointerEvent event) {
setState(() {
_points = List.from(_points)..add([event.localPosition,_pointSize]);
});
}
void _handlePointerUp(PointerEvent event) {
setState(() {
_points = List.from(_points)..add([event.localPosition,_pointSize]);
});
}
void _changePointSize(double value) {
setState(() {
_pointSize = value;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Canvas'),
),
body: Listener(
onPointerDown: _handlePointerDown,
onPointerMove: _handlePointerMove,
onPointerUp: _handlePointerUp,
child: CustomPaint(
painter: CanvasPainter(_points),
size: Size.infinite,
),
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
_changePointSize(5.0);
},
),
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
_changePointSize(10.0);
},
),
IconButton(
icon: const Icon(Icons.brush),
onPressed: () {
_changePointSize(15.0);
},
),
],
),
),
);
}
}
class CanvasPainter extends CustomPainter {
List<dynamic> points;
CanvasPainter(this.points);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.blue
..strokeCap = StrokeCap.round;
for (int i = 0; i < points.length - 1; i++) {
paint.strokeWidth = points[i][1];
canvas.drawLine(points[i][0], points[i + 1][0], paint);
}
}
@override
bool shouldRepaint(CanvasPainter oldDelegate) => true;
}