在实现手写的基础上 增加橡皮擦功能
详情见代码
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as UI;
class HandWrittenBoard extends StatefulWidget {
///手写笔颜色
final Color? painColor;
///手写笔宽度
final double? paintWidth;
///橡皮
final double? clearWidth;
final double? clearDx;
final double? clearDy;
///手写笔控制器
final HandWrittenBoardController boardController;
const HandWrittenBoard(
{Key? key,
this.painColor,
this.clearWidth,
this.paintWidth,
required this.boardController,
this.clearDx,
this.clearDy})
: super(key: key);
@override
_HandWrittenBoardState createState() => _HandWrittenBoardState();
}
class HandWrittenBoardController extends ChangeNotifier {
late BuildContext _context;
late List strokes = [];
void bindContext(BuildContext context) {
_context = context;
}
Future? get uiImage {
UI.PictureRecorder recorder = UI.PictureRecorder();
Canvas canvas = Canvas(recorder);
BoardPainter painter = BoardPainter();
Size size = _context.size!;
painter.paint(canvas, size);
return recorder
.endRecording()
.toImage(size.width.floor(), size.height.floor());
}
void refStrokes(List newValue) {
if (strokes != newValue) {
strokes = newValue;
}
notifyListeners();
}
void clearBoard() {
strokes.clear();
notifyListeners();
}
}
class _HandWrittenBoardState extends State {
List _strokes = [];
@override
void initState() {
super.initState();
widget.boardController.bindContext(context);
}
void _onUpdate(DragUpdateDetails details) {
if (isClear) {
dx = details.localPosition.dx;
dy = details.localPosition.dy;
}
setState(() {
_strokes.last.path
.lineTo(details.localPosition.dx, details.localPosition.dy);
});
widget.boardController.refStrokes(_strokes);
}
void _start(double startX, double startY) {
if (isClear) {
dx = startX;
dy = startY;
}
final newStroke = Stroke(
color: widget.painColor!,
width: widget.paintWidth!,
isClear: isClear,
);
newStroke.path.moveTo(startX, startY);
_strokes.add(newStroke);
widget.boardController.refStrokes(_strokes);
}
late double dx = widget.clearDx! + widget.clearWidth! / 2;
late double dy = widget.clearDy! - widget.clearWidth! / 2;
bool isClear = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanUpdate: _onUpdate,
onPanStart: (details) => _start(
details.localPosition.dx,
details.localPosition.dy,
),
onPanDown: (detail) {
Rect rect =
Rect.fromCenter(center: Offset(dx, dy), width: 50, height: 50);
isClear = rect.contains(detail.localPosition);
},
child: Stack(
children: [
CustomPaint(
painter: BoardPainter(
strokes: _strokes,
clearWidth: widget.clearWidth,
),
size: Size.infinite,
),
Positioned(
child: Container(
width: widget.clearWidth,
height: widget.clearWidth,
color: Colors.red,
),
left: dx - widget.clearWidth! / 2,
top: dy - widget.clearWidth! / 2,
),
],
),
);
}
}
class Stroke {
final path = Path();
final Color color;
final double width;
final bool isClear;
Stroke({
this.color = Colors.black,
this.width = 4,
this.isClear = false,
});
}
class BoardPainter extends CustomPainter {
BoardPainter({
this.strokes,
this.clearWidth,
});
final List? strokes;
final double? clearWidth;
@override
void paint(Canvas canvas, Size size) {
canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
Paint()..color = Colors.white,
);
canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), Paint());
for (final stroke in strokes!) {
final paint = Paint()
..strokeWidth = stroke.isClear ? clearWidth! : stroke.width
..color = stroke.isClear ? Colors.transparent : stroke.color
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..blendMode = stroke.isClear ? BlendMode.clear : BlendMode.srcOver;
canvas.drawPath(stroke.path, paint);
}
canvas.restore();
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
使用示范
import 'package:flitter_okgo/hand_written_board.dart';
import 'package:flutter/material.dart';
class HandWrittenBoardPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State {
HandWrittenBoardController controller = HandWrittenBoardController();
@override
void initState() {
super.initState();
}
Widget get initFloatingActionButton {
return FloatingActionButton(
backgroundColor: Colors.grey,
elevation: 1,
focusElevation: 1,
onPressed: () {
controller.clearBoard();
},
child: Icon(Icons.clear),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: initFloatingActionButton,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
appBar: AppBar(
title: Text("橡皮擦"),
),
body: HandWrittenBoard(
boardController: controller,
clearWidth: 50,
paintWidth: 5,
painColor: Colors.green,
clearDx: 0,
clearDy: 200,
),
);
}
}