2017-08-08 87 views
1

在这里颤抖新手。我目前正在尝试使用Flutter构建一个简单的触摸绘图应用程序,但无法解决如何触发画布重新绘制的问题。如何触摸油漆画布?

我有这个: 我有一个CustomPaint小部件,其中包含一个GestureDetector子。 CustomPaint的画家在发生触摸事件时会收到消息,并存储触摸坐标以在重新绘制时绘制路径。问题是,绘画方法永远不会被调用。

这是我的代码至今:

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

根据CustomPainter docs只要需要

最有效的方法重新绘制触发重绘必须通知漆小部件是可以扩展此类并为CustomPainter的构造函数提供重绘参数,其中该对象通知其侦听器何时需要重绘,或者扩展Listenable(例如,通过ChangeNotifier)并实现CustomPainter,以便该对象本身直接提供通知。无论哪种情况,只要动画打勾,CustomPaint小部件或RenderCustomPaint渲染对象都将侦听Listenable并重绘,避免了管道的构建和布局阶段。

例如, 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, 
    ); 
    } 
}