Flutter:如何通知CustomPainter重绘?

Sam*_*Sam 3 flutter

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

三个按钮

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

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;
}
Run Code Online (Sandbox Code Playgroud)

我认为我需要class DiagramPainter extends ChangeNotifier implements CustomPainter而不是class DiagramPainter extends CustomPainter

我还认为我需要通过 触发重绘notifyListeners()。在这种情况下,谁会收到通知?仍然如此DiagramPainter,不是吗?我缺少什么?

相关: 1 , 2 .

chu*_*han 5


您可以在第 1 步下面复制粘贴运行完整代码:DiagramPainter({Listenable repaint}) : super(repaint: repaint)
第 2 步:传递ValueNotifier<int>(0);DiagramPainter(repaint: _counter)
第 4 步:onTapUp调用中_counter.value++;
代码片段

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) {
Run Code Online (Sandbox Code Playgroud)

工作演示

在此输入图像描述

完整代码

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;
}
Run Code Online (Sandbox Code Playgroud)