在这里吵架新手。我目前正在尝试使用Flutter构建一个简单的触摸绘图应用程序,但无法确定如何触发画布重绘。
我拥有的是: 我有一个包含GestureDetector子项的CustomPaint小部件。每当触摸事件发生时,CustomPaint的画家都会收到消息,并存储触摸坐标以在重新绘制时绘制路径。问题是,从不调用paint方法。
这是我到目前为止的代码:
import 'package:flutter/material.dart';
class WriteScreen extends StatefulWidget {
@override
_WriteScreenState createState() => new _WriteScreenState();
}
class KanjiPainter extends CustomPainter {
Color strokeColor;
var strokes = new List<List<Offset>>();
KanjiPainter( this.strokeColor );
void startStroke(Offset position) {
print("startStroke");
strokes.add([position]);
}
void appendStroke(Offset position) {
print("appendStroke");
var stroke = strokes.last;
stroke.add(position);
}
void endStroke() {
}
@override
void paint(Canvas canvas, Size size) {
print("paint!");
var rect = Offset.zero & size;
Paint fillPaint = new Paint();
fillPaint.color = Colors.yellow[100];
fillPaint.style = PaintingStyle.fill;
canvas.drawRect(
rect,
fillPaint
);
Paint strokePaint = new Paint();
strokePaint.color = Colors.black;
strokePaint.style = PaintingStyle.stroke;
for (var stroke in strokes) {
Path strokePath = new Path();
// Iterator strokeIt = stroke.iterator..moveNext();
// Offset start = strokeIt.current;
// strokePath.moveTo(start.dx, start.dy);
// while (strokeIt.moveNext()) {
// Offset off = strokeIt.current;
// strokePath.addP
// }
strokePath.addPolygon(stroke, false);
canvas.drawPath(strokePath, strokePaint);
}
}
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class _WriteScreenState extends State<WriteScreen> {
GestureDetector touch;
CustomPaint canvas;
KanjiPainter kanjiPainter;
void panStart(DragStartDetails details) {
print(details.globalPosition);
kanjiPainter.startStroke(details.globalPosition);
}
void panUpdate(DragUpdateDetails details) {
print(details.globalPosition);
kanjiPainter.appendStroke(details.globalPosition);
}
void panEnd(DragEndDetails details) {
kanjiPainter.endStroke();
}
@override
Widget build(BuildContext context) {
touch = new GestureDetector(
onPanStart: panStart,
onPanUpdate: panUpdate,
onPanEnd: panEnd,
);
kanjiPainter = new KanjiPainter( const Color.fromRGBO(255, 255, 255, 1.0) );
canvas = new CustomPaint(
painter: kanjiPainter,
child: touch,
// child: new Text("Custom Painter"),
// size: const Size.square(100.0),
);
Container container = new Container(
padding: new EdgeInsets.all(20.0),
child: new ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: new Card(
elevation: 10.0,
child: canvas,
)
)
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Draw!")
),
backgroundColor: const Color.fromRGBO(200, 200, 200, 1.0),
body: container,
);
}
}
答案 0 :(得分:2)
根据CustomPainter docs,您必须在需要重新绘制时通知绘制小部件
触发重绘的最有效方法是扩展此类并为CustomPainter的构造函数提供重绘参数,该对象在重新绘制或扩展Listenable时通知其侦听器(例如,通过ChangeNotifier)并实现CustomPainter,以便对象本身直接提供通知。在任何一种情况下,CustomPaint小部件或RenderCustomPaint渲染对象都会在动画滴答时监听Listenable并重新绘制,从而避免了管道的构建和布局阶段。
E.g。 KanjiPainter
应扩展ChangeNotifier
并实施CustomPainter
。当你改变笔画时,调用notifyListeners
此外,build
函数始终会创建新的KanjiPainter
,这将删除所有旧数据。您可以在initState
一次初始化画家。
工作示例:
class WriteScreen extends StatefulWidget {
@override
_WriteScreenState createState() => new _WriteScreenState();
}
class KanjiPainter extends ChangeNotifier implements CustomPainter {
Color strokeColor;
var strokes = new List<List<Offset>>();
KanjiPainter(this.strokeColor);
bool hitTest(Offset position) => null;
void startStroke(Offset position) {
print("startStroke");
strokes.add([position]);
notifyListeners();
}
void appendStroke(Offset position) {
print("appendStroke");
var stroke = strokes.last;
stroke.add(position);
notifyListeners();
}
void endStroke() {
notifyListeners();
}
@override
void paint(Canvas canvas, Size size) {
print("paint!");
var rect = Offset.zero & size;
Paint fillPaint = new Paint();
fillPaint.color = Colors.yellow[100];
fillPaint.style = PaintingStyle.fill;
canvas.drawRect(rect, fillPaint);
Paint strokePaint = new Paint();
strokePaint.color = Colors.black;
strokePaint.style = PaintingStyle.stroke;
for (var stroke in strokes) {
Path strokePath = new Path();
// Iterator strokeIt = stroke.iterator..moveNext();
// Offset start = strokeIt.current;
// strokePath.moveTo(start.dx, start.dy);
// while (strokeIt.moveNext()) {
// Offset off = strokeIt.current;
// strokePath.addP
// }
strokePath.addPolygon(stroke, false);
canvas.drawPath(strokePath, strokePaint);
}
}
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class _WriteScreenState extends State<WriteScreen> {
GestureDetector touch;
CustomPaint canvas;
KanjiPainter kanjiPainter;
void panStart(DragStartDetails details) {
print(details.globalPosition);
kanjiPainter.startStroke(details.globalPosition);
}
void panUpdate(DragUpdateDetails details) {
print(details.globalPosition);
kanjiPainter.appendStroke(details.globalPosition);
}
void panEnd(DragEndDetails details) {
kanjiPainter.endStroke();
}
@override
void initState() {
super.initState();
kanjiPainter = new KanjiPainter(const Color.fromRGBO(255, 255, 255, 1.0));
}
@override
Widget build(BuildContext context) {
touch = new GestureDetector(
onPanStart: panStart,
onPanUpdate: panUpdate,
onPanEnd: panEnd,
);
canvas = new CustomPaint(
painter: kanjiPainter,
child: touch,
// child: new Text("Custom Painter"),
// size: const Size.square(100.0),
);
Container container = new Container(
padding: new EdgeInsets.all(20.0),
child: new ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: new Card(
elevation: 10.0,
child: canvas,
)));
return new Scaffold(
appBar: new AppBar(title: new Text("Draw!")),
backgroundColor: const Color.fromRGBO(200, 200, 200, 1.0),
body: container,
);
}
}
答案 1 :(得分:0)