【问题标题】:Flutter: How to notify CustomPainter to redraw?Flutter:如何通知 CustomPainter 重绘?
【发布时间】:2021-02-23 05:53:44
【问题描述】:

在下面的代码中,我尝试在画布上模拟小部件。

当一个小部件/按钮被触摸时,它会在两种颜色之间翻转。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Diagram',
      theme: ThemeData(
        appBarTheme: AppBarTheme(color: Colors.blueAccent,),
      ),
      home: Diagram(),
    );
  }
}

class Diagram extends StatefulWidget {
  @override
  _DiagramState createState() => new _DiagramState();
}

class _DiagramState extends State<Diagram> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Canvas Widgets'),
        centerTitle: true,
      ),
      body: Center(
        child: GestureDetector(
          onTapUp: (TapUpDetails details) {
            setState(() {
                ;
            });
          },
          child: AspectRatio(
            aspectRatio: 1.0,
            child: Container(
              child: CustomPaint(
                painter: DiagramPainter(),
              ),
            ),
          ),
        ),
      ),
    );
  }

}

class DiagramPainter extends CustomPainter {
// class DiagramPainter extends ChangeNotifier implements CustomPainter {
  DiagramPainter() {
    for(int i=0; i<_numberOfButtons; i++) {
      state.add(false);
    }
  }

  static final int _numberOfButtons = 3;
  static final double _margin = 60;
  static final double _gap = _margin / 2.0 / _numberOfButtons.toDouble();
  double width;
  double y;

  static Canvas currentCanvas;

  var buttons = [];
  var state = [];

  final bluePaint = Paint()
    ..color = Colors.blue;
  final yellowPaint = Paint()
    ..color = Colors.yellow;

  @override
  void paint(Canvas canvas, Size size) {
    currentCanvas = canvas;
    width = (size.width - _margin) /_numberOfButtons.toDouble();
    y = size.height / 2.0 - width / 2.0;

    Iterable<int>.generate(_numberOfButtons).toList().forEach((index) {
      buttons.add(drawButton(canvas, index));
    });
  }

  Rect drawButton(Canvas canvas, int index) {
    double left = _gap + index * (width + _gap * 2.0);

    var rect = Rect.fromLTWH(left, y, width, width);
    var paint = state[index] ? yellowPaint : bluePaint;
    canvas.drawOval(rect, paint);
    return rect;
  }

  @override
  bool hitTest(Offset position) {
    for(int i=0; i<_numberOfButtons; i++) {
      if (buttons[i].contains(position)) {
        state[i] = !state[i];
        // trigger redraw
        // notifyListeners();
        return true;
      }
    }
    return false;
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

我发现我需要class DiagramPainter extends ChangeNotifier implements CustomPainter 而不是class DiagramPainter extends CustomPainter

我还收集到我需要通过notifyListeners() 触发重绘。在这种情况下通知谁?它仍然是DiagramPainter,不是吗?我错过了什么?

相关: 1, 2.

【问题讨论】:

  • 要么 1) 将 Listenable 传递给 CustomPainter 构造函数(通过可选的 repaint 命名参数)或 2) class DiagramPainter extends CustomPainter with ChangeNotifier 并在需要时调用 notifyListeners()
  • @pskink 好吧,我实际上是在画布中寻找一组完全动态的小部件。所以 :-) 要么 1)我接受 Chunhunghan 的回答,考虑到我写当前问题的方式,这完全没问题,然后问续集;或者 2)你向我们展示了细节(魔鬼 is 在详细信息)通过写一个答案。
  • @pskink 我认为 2) 更好,因为我们可以背靠背地研究和比较这两种技术。
  • @pskink 完成了对许多代码异味的更正。不错!
  • @pskink 我在您的代码中看到了几个优点,但我仍然很难过。 ChangeNotifier mixin 的存在如何使 notifyListeners() 调用 paint()?例如,paint() 是否以某种方式声明为CustomPainter 的待通知更改代理?

标签: flutter


【解决方案1】:

您可以在下面复制粘贴运行完整代码
第 1 步:DiagramPainter({Listenable repaint}) : super(repaint: repaint)
第 2 步:将 ValueNotifier&lt;int&gt;(0); 传递给 DiagramPainter(repaint: _counter)
第 4 步:在onTapUp 中致电_counter.value++;
代码sn-p

class _DiagramState extends State<Diagram> {
  final _counter = ValueNotifier<int>(0);

  @override
  Widget build(BuildContext context) {
    ...
        child: GestureDetector(
          onTapUp: (TapUpDetails details) {
            _counter.value++;               
          },
          child: ...
              child: CustomPaint(
                painter: DiagramPainter(repaint: _counter),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class DiagramPainter extends CustomPainter {    
  DiagramPainter({Listenable repaint}) : super(repaint: repaint) {

工作演示

完整代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Diagram',
      theme: ThemeData(
        appBarTheme: AppBarTheme(
          color: Colors.blueAccent,
        ),
      ),
      home: Diagram(),
    );
  }
}

class Diagram extends StatefulWidget {
  @override
  _DiagramState createState() => new _DiagramState();
}

class _DiagramState extends State<Diagram> {
  final _counter = ValueNotifier<int>(0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Canvas Widgets'),
        centerTitle: true,
      ),
      body: Center(
        child: GestureDetector(
          onTapUp: (TapUpDetails details) {
            _counter.value++;
            /*setState(() {
              ;
            });*/
          },
          child: AspectRatio(
            aspectRatio: 1.0,
            child: Container(
              child: CustomPaint(
                painter: DiagramPainter(repaint: _counter),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class DiagramPainter extends CustomPainter {
// class DiagramPainter extends ChangeNotifier implements CustomPainter {
  DiagramPainter({Listenable repaint}) : super(repaint: repaint) {
    for (int i = 0; i < _numberOfButtons; i++) {
      state.add(false);
    }
  }

  static final int _numberOfButtons = 3;
  static final double _margin = 60;
  static final double _gap = _margin / 2.0 / _numberOfButtons.toDouble();
  double width;
  double y;

  static Canvas currentCanvas;

  var buttons = [];
  var state = [];

  final bluePaint = Paint()..color = Colors.blue;
  final yellowPaint = Paint()..color = Colors.yellow;

  @override
  void paint(Canvas canvas, Size size) {
    currentCanvas = canvas;
    width = (size.width - _margin) / _numberOfButtons.toDouble();
    y = size.height / 2.0 - width / 2.0;

    Iterable<int>.generate(_numberOfButtons).toList().forEach((index) {
      buttons.add(drawButton(canvas, index));
    });
  }

  Rect drawButton(Canvas canvas, int index) {
    double left = _gap + index * (width + _gap * 2.0);

    var rect = Rect.fromLTWH(left, y, width, width);
    var paint = state[index] ? yellowPaint : bluePaint;
    canvas.drawOval(rect, paint);
    return rect;
  }

  @override
  bool hitTest(Offset position) {
    for (int i = 0; i < _numberOfButtons; i++) {
      if (buttons[i].contains(position)) {
        state[i] = !state[i];
        // trigger redraw
        // notifyListeners();
        return true;
      }
    }
    return false;
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

【讨论】:

    猜你喜欢
    • 2022-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 2019-12-29
    • 2020-05-28
    • 2016-05-17
    • 2021-07-27
    相关资源
    最近更新 更多