如何触摸画布?

时间:2017-08-08 21:20:08

标签: dart flutter

在这里吵架新手。我目前正在尝试使用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,
    );
  }
}

2 个答案:

答案 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)

this库很好。

示例:

unique