【问题标题】:Changing colour of CustomPaint changes for all previous points更改所有先前点的 CustomPaint 更改颜色
【发布时间】:2018-11-07 09:20:05
【问题描述】:

所以我正在尝试按照“签名画布”方法使用 Flutter 创建一个绘图应用程序。但是,我无法更改 CustomPaint 对象的颜色,而无需在更改之前更改每个线条绘制的颜色,如下所示:

如您所见,一旦页面小部件的状态发生更改(通过单击主 FAB 或我再次在画布上绘制),颜色就会发生变化。下面是我的 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 对象并以这种方式更新 color 属性,但这也破坏了“绘制”手势。

任何帮助将不胜感激!

另外,这里是我的 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;
}

【问题讨论】:

    标签: android canvas colors dart flutter


    【解决方案1】:

    2020,我对此有一个很好的解决方案,因为实际选择的方法对我不起作用,而且我看到了一些多余的调用。

    所以,我开始创建一个小类:

    class _GroupPoints {
      Offset offset;
      Color color;
      _GroupPoints({this.offset, this.color});
    }
    

    接下来,我像这样声明我的CustomPainter

    class Signature extends CustomPainter {
      List<_GroupPoints> points;
      Color color;
      Signature({
        this.color,
        this.points,
      });
    
      @override
      void paint(Canvas canvas, Size size) {
        Paint paint = new Paint()
           // if you need this next params as dynamic, you can move it inside the for part
          ..strokeCap = StrokeCap.round
          ..strokeWidth = 5.0;
    
        for (int i = 0; i < newPoints.length - 1; i++) {
          paint.color = points[i].color;
          if (points[i].offset != null && points[i + 1].offset != null) {
            canvas.drawLine(points[i].offset, points[i + 1].offset, paint);
          }
          canvas.clipRect(Offset.zero & size);
        }
      }
    
      @override
      bool shouldRepaint(Signature oldDelegate) => true;
    }
    

    在我的小部件上:

    ...
    class _MyPageState extends State<MyPage> {
      ...
      List<_GroupPoints> points = [];
      ...
    
                               Container(
                                      height: 500,
                                      width: double.infinity,
                                      child: GestureDetector(
                                        onPanUpdate: (DragUpdateDetails details) {
                                          setState(() {
                                            points = new List.from(points)
                                              ..add(
                                                new _GroupPoints(
                                                  offset: details.localPosition,
                                                  color: myDynamicColor,
                                                ),
                                              );
                                          });
                                        },
                                        onPanEnd: (DragEndDetails details) {
                                          points.add(
                                            _GroupPoints(
                                                color: myDynamicColor,
                                                offset: null),
                                          );
                                        },
                                        child: CustomPaint(
                                          painter: Signature(
                                            newPoints: points,
                                            color: myDynamicColor,
                                          ),
                                        ),
                                      ),
                                    ),
                                  }
    

    通过这种方式,我们可以使用各自颜色的多个点绘制。希望这可以帮助任何人。

    【讨论】:

    • 我刚试过这个,它工作正常。我面临的唯一问题是,在画了几条线之后,应用程序变得非常滞后。我正在尝试优化它,但到目前为止还没有运气。
    【解决方案2】:

    我认为,对于不同的颜色,您必须使用不同的颜料。我已经对您的代码进行了一些小改动,它可以工作。

    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;
    }
    

    【讨论】:

    • 伟大的会试试这个!刚刚升级到 0.10.2 并遇到了一些模拟器问题,但希望不会太长。
    猜你喜欢
    • 2012-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 2021-10-08
    • 2023-03-12
    • 2023-03-15
    • 2018-02-24
    相关资源
    最近更新 更多