2017-08-08 121 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, 
    ); 
    } 
}