2017-10-12 50 views
2

我有一個顯示該點處的黑點,其中用戶觸摸屏幕像這樣的應用程序:如何確保我的CustomPaint小部件繪畫存儲在柵格緩存中?

enter image description here

黑點可以由用戶移動他/她拖動他的手指上屏幕。

背景是一個昂貴的繪畫操作,所以我在堆棧中創建了兩個單獨的小部件,希望背景小部件繪畫將存儲在Flutter柵格緩存中。但它不存儲 - 每次黑點移動時,Flutter都會調用我昂貴的繪畫方法。

我在做什麼錯?

這裏是我的代碼:

import 'package:flutter/material.dart'; 
import 'dart:math'; 

void main() { 
    runApp(new MyApp()); 
} 

class MyApp extends StatelessWidget { 
    @override 
    Widget build(BuildContext context) { 
    return new MaterialApp(
     home: new MyHomePage(), 
    ); 
    } 
} 

class MyHomePage extends StatefulWidget { 
    @override 
    State createState() => new MyHomePageState(); 
} 

class MyHomePageState extends State<MyHomePage> { 
    GlobalKey _paintKey = new GlobalKey(); 
    Offset _offset; 

    @override 
    Widget build(BuildContext context) { 
    return new Scaffold(
     body: new Stack(
     fit: StackFit.expand, 
     children: <Widget>[ 
      new CustomPaint(
      painter: new ExpensivePainter(), 
      isComplex: true, 
      willChange: false, 
     ), 
      new Listener(
      onPointerDown: _updateOffset, 
      onPointerMove: _updateOffset, 
      child: new CustomPaint(
       key: _paintKey, 
       painter: new MyCustomPainter(_offset), 
       child: new ConstrainedBox(
       constraints: new BoxConstraints.expand(), 
      ), 
      ), 
     ) 
     ], 
    ), 
    ); 
    } 

    _updateOffset(PointerEvent event) { 
    RenderBox referenceBox = _paintKey.currentContext.findRenderObject(); 
    Offset offset = referenceBox.globalToLocal(event.position); 
    setState(() { 
     _offset = offset; 
    }); 
    } 
} 

class ExpensivePainter extends CustomPainter { 
    @override 
    void paint(Canvas canvas, Size size) { 
    print("Doing expensive paint job"); 
    Random rand = new Random(12345); 
    List<Color> colors = [ 
     Colors.red, 
     Colors.blue, 
     Colors.yellow, 
     Colors.green, 
     Colors.white, 
    ]; 
    for (int i = 0; i < 5000; i++) { 
     canvas.drawCircle(
      new Offset(
       rand.nextDouble() * size.width, rand.nextDouble() * size.height), 
      10 + rand.nextDouble() * 20, 
      new Paint() 
      ..color = colors[rand.nextInt(colors.length)].withOpacity(0.2)); 
    } 
    } 

    @override 
    bool shouldRepaint(ExpensivePainter other) => false; 
} 

class MyCustomPainter extends CustomPainter { 
    final Offset _offset; 

    MyCustomPainter(this._offset); 

    @override 
    void paint(Canvas canvas, Size size) { 
    if (_offset == null) return; 
    canvas.drawCircle(_offset, 10.0, new Paint()..color = Colors.black); 
    } 

    @override 
    bool shouldRepaint(MyCustomPainter other) => other._offset != _offset; 
} 
+0

順便說一句,你爲什麼用'Listener'爲DRAP /下降?爲此,有一個'Draggable'小部件。 – Darky

+0

感謝您的提示 - 我沒有意識到Draggable,但它並不適合我的情況:我實際上爲我的協作白板webapp寫了一個Flutter應用程序:https://whiteboardfox.com/ – Mark

回答

7

它顫動的特異性。我們沒有反應,只有當他們的狀態/道具改變時纔會重新繪製「組件」。

在撲,每一個時代都有小部件重新繪製整個樹也會這樣做的。

通常,這不是一個問題,而且相當快。但是有些情況下(比如你的情況),你不需要。這是一個相當無證的小部件,但重要的是出現! RepaintBoundary

有一個很好的談撲動的渲染管線是如何在這裏工作:https://www.youtube.com/watch?v=UUfXWzp0-DU

但在短期,考慮RepaintBoundary因爲什麼告訴撲噴塗操作分成不同的部分。

無論如何,解決方案? 將您的Expensive小部件包裝在RepaintBoundary中。突然你會得到60 FPS。

 new RepaintBoundary(
     child: new CustomPaint(
      painter: new ExpensivePainter(), 
      isComplex: true, 
      willChange: false, 
     ), 
    ), 

enter image description here

+0

這很有用 - 謝謝!還要感謝關於重新繪製邊界部分的書籤上的視頻鏈接:) – Mark

相關問題