簡體   English   中英

更改 CustomPaint 的顏色更改所有以前的點

[英]Changing colour of CustomPaint changes for all previous points

所以我試圖按照“簽名畫布”方法使用 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 對象並以這種方式更新顏色屬性,但這也會破壞“繪制”手勢。

任何幫助將不勝感激!

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

我認為,對於不同的顏色,您必須使用不同的油漆。 我對您的代碼進行了一些小的更改,它有效。

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

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,
                                      ),
                                    ),
                                  ),
                                ),
                              }

通過這種方式,我們可以使用具有各自顏色的多個點繪制。 希望這可以幫助任何人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM