android - 更改 CustomPaint 的颜色会更改所有先前的点

标签 android canvas colors dart flutter

因此,我正在尝试按照“签名 Canvas ”方法使用 Flutter 创建一个绘图应用程序。但是,我无法更改 CustomPaint 对象的颜色,而它在更改之前已经更改了每条线条绘制的颜色,如下所示: enter image description here

如您所见,一旦页面小部件的状态发生变化(通过单击主 FAB 或再次在 Canvas 上绘制),颜色就会发生变化。下面是我的 DrawPage 代码:

class DrawPage extends StatefulWidget {
  @override
  DrawPageState createState() => new DrawPageState();
}

class DrawPageState extends State<DrawPage> with TickerProviderStateMixin {
  AnimationController controller;
  List<Offset> points = <Offset>[];
  Color color = Colors.black;
  StrokeCap strokeCap = StrokeCap.round;
  double strokeWidth = 5.0;

  @override
  void initState() {
    super.initState();
    controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 500),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: GestureDetector(
          onPanUpdate: (DragUpdateDetails details) {
            setState(() {
              RenderBox object = context.findRenderObject();
              Offset localPosition =
                  object.globalToLocal(details.globalPosition);
              points = new List.from(points);
              points.add(localPosition);
            });
          },
          onPanEnd: (DragEndDetails details) => points.add(null),
          child: CustomPaint(
            painter: Painter(
                points: points,
                color: color,
                strokeCap: strokeCap,
                strokeWidth: strokeWidth),
            size: Size.infinite,
          ),
        ),
      ),
      floatingActionButton:
          Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
        Container(
          height: 70.0,
          width: 56.0,
          alignment: FractionalOffset.topCenter,
          child: ScaleTransition(
            scale: CurvedAnimation(
              parent: controller,
              curve: Interval(0.0, 1.0 - 0 / 3 / 2.0, curve: Curves.easeOut),
            ),
            child: FloatingActionButton(
              mini: true,
              child: Icon(Icons.clear),
              onPressed: () {
                points.clear();
              },
            ),
          ),
        ),
        Container(
          height: 70.0,
          width: 56.0,
          alignment: FractionalOffset.topCenter,
          child: ScaleTransition(
            scale: CurvedAnimation(
              parent: controller,
              curve: Interval(0.0, 1.0 - 1 / 3 / 2.0, curve: Curves.easeOut),
            ),
            child: FloatingActionButton(
              mini: true,
              child: Icon(Icons.lens),
              onPressed: () {},
            ),
          ),
        ),
        Container(
            height: 70.0,
            width: 56.0,
            alignment: FractionalOffset.topCenter,
            child: ScaleTransition(
                scale: CurvedAnimation(
                  parent: controller,
                  curve:
                      Interval(0.0, 1.0 - 2 / 3 / 2.0, curve: Curves.easeOut),
                ),
                child: FloatingActionButton(
                    mini: true,
                    child: Icon(Icons.color_lens),
                    onPressed: () async {
                      Color temp;
                      temp = await showDialog(
                          context: context,
                          builder: (context) => ColorDialog());
                      if (temp != null) {
                        setState(() {
                          color = temp;
                        });
                      }
                    }))),
        FloatingActionButton(
          child: AnimatedBuilder(
            animation: controller,
            builder: (BuildContext context, Widget child) {
              return Transform(
                transform: Matrix4.rotationZ(controller.value * 0.5 * math.pi),
                alignment: FractionalOffset.center,
                child: Icon(Icons.brush),
              );
            },
          ),
          onPressed: () {
            if (controller.isDismissed) {
              controller.forward();
            } else {
              controller.reverse();
            }
          },
        ),
      ]),
    );
  }
}

到目前为止我尝试了什么:

我试过如何将这些点添加到我的偏移列表中,因为在每次“绘制”手势后都会重新创建此列表,例如仅添加到当前列表而不重新创建它,但这会破坏“绘制”手势:

setState(() {
  RenderBox object = context.findRenderObject();
  Offset localPosition =
     object.globalToLocal(details.globalPosition);
  points = new List.from(points);
  points.add(localPosition);
});

我已经尝试在 build() 范围之外引用 CustomPaint 对象或我的 Painter 对象并以这种方式更新颜色属性,但这也会破坏“绘制”手势。

任何帮助将不胜感激!

此外,这里是我的 Painter 类的代码,以防人们希望看到它:

class Painter extends CustomPainter {
  List<Offset> points;
  Color color;
  StrokeCap strokeCap;
  double strokeWidth;

  Painter({this.points, this.color, this.strokeCap, this.strokeWidth});

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = new Paint();
    paint.color = color;
    paint.strokeCap = strokeCap;
    paint.strokeWidth = strokeWidth;    

    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null) {
        canvas.drawLine(points[i], points[i + 1], paint);
      }
    }
  }

  @override
  bool shouldRepaint(Painter oldPainter) => oldPainter.points != points;
}

最佳答案

我认为,对于不同的颜色,您必须使用不同的 Paints。我对您的代码进行了一些小改动,效果很好。

class DrawPageState extends State<DrawPage> with TickerProviderStateMixin {
  ...
  List<Painter> painterList = [];

  @override
  Widget build(BuildContext context) {
    ...
          child: CustomPaint(
            painter: Painter(
                points: points, color: color, strokeCap: strokeCap, strokeWidth: strokeWidth, painters: painterList),
            size: Size.infinite,
          ),
    ...
                onPressed: () async {
                  Color temp;
                  temp = await showDialog(
                      context: context,
                      builder: (context) => ColorDialog());
                  if (temp != null) {
                    setState(() {
                      painterList
                          .add(Painter(points: points.toList(), color: color, strokeCap: strokeCap, strokeWidth: strokeWidth));
                      points.clear();
                      strokeCap = StrokeCap.round;
                      strokeWidth = 5.0;
                      color = temp;
                    });
                  }
    ...
  }
}

class Painter extends CustomPainter {
  List<Offset> points;
  Color color;
  StrokeCap strokeCap;
  double strokeWidth;
  List<Painter> painters;

  Painter({this.points, this.color, this.strokeCap, this.strokeWidth, this.painters = const []});

  @override
  void paint(Canvas canvas, Size size) {
    for (Painter painter in painters) {
      painter.paint(canvas, size);
    }

    Paint paint = new Paint()
      ..color = color
      ..strokeCap = strokeCap
      ..strokeWidth = strokeWidth;
    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null) {
        canvas.drawLine(points[i], points[i + 1], paint);
      }
    }
  }

  @override
  bool shouldRepaint(Painter oldDelegate) => oldDelegate.points != points;
}

关于android - 更改 CustomPaint 的颜色会更改所有先前的点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53186525/

相关文章:

javascript - 当我想创建圆形时,为什么我的 Canvas 会创建椭圆?

javascript - Javascript 中奇怪的 Canvas 维度 (html 5/jquery)

java - 如何使用java和opencv检测png文件中的颜色?

android - Vungle 视频广告不适用于某些设备

android - 如何禁用仅右抽屉导航的滑动?

android - ffmpeg 缺少混合过滤器

javascript - 仅当代码在本地打开时才能保存 Canvas ,在线查看时不能保存 Canvas

HTML CSS 无法正常工作

具有发散调色板的 R 热图

java - 获取 DialogFragment 的 View