Почему «points.clear» и «points.add» (точки - это список смещения) не работают одинаково в 10-й пробной версии CustomPaint во Flutter?

Он работает для некоторых испытаний, затем не работает для некоторых испытаний, а затем снова работает (без какого-либо конкретного шаблона). Я имею в виду, например, что он исправляет линию и рисует идеальную линию 3-4 раза, используя только первую и последнюю точку, а затем на один раз он покидает линию, которую нарисовал пользователь. Кажется, что points.clear или же points.addиногда работает, а иногда нет. Я знаю, это звучит глупо, но я не могу объяснить это логически. Я был бы очень благодарен, если бы кто-нибудь мог взглянуть на код и рассказать мне, что происходит.

вот мой GestureDetector:

      body: GestureDetector(
        onPanDown: (DragDownDetails details) {
          setState(() {
            points.clear();
          });
        },
        onPanUpdate: (DragUpdateDetails details) {
          //when the user touch the screen and move
          setState(() {
            RenderBox box = context.findRenderObject(); //finds the scaffold
            Offset point = box.globalToLocal(details.globalPosition);
            point = point.translate(0.0, -(AppBar().preferredSize.height + 30));

            points = List.from(points)
              ..add(point); //add the points when user drag in screen
            firstPoint = points.first; //storing the first point for drawing the line
          });
        },
        onPanEnd: (DragEndDetails details) {
          setState(() {
            if (mode == "Line") {
              Offset lastPoint = points.last; //storing the last point for drawing the line
              points.clear();
              points.add(firstPoint);
              points.add(lastPoint);
              points.add(null);
            } 
          });
        },
        child: sketchArea,
      ),

и вот мой класс CustomPainter:

      class Sketcher2 extends CustomPainter {
  final List<Offset> points;
  Sketcher2(this.points);

  @override
  bool shouldRepaint(Sketcher2 oldDelegate) {
    return oldDelegate.points != points;
  }

  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.black //seting the color of the drawing
      ..strokeCap = StrokeCap.round //the shape of a single dot (single touch)
      ..strokeWidth = 4.0; // the width of a single dot (single touch)

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

2 ответа

У вас может быть проблема с shouldRepaint вашей Sketcher2:

      @override
bool shouldRepaint(Sketcher2 oldDelegate) {
  return oldDelegate.points != points;
}

В !=оператор сравнивает объекты. Он вернет истину тогда и только тогда, когда oldDelegate.points и не являются одним и тем же объектом.

На самом деле, я очень удивлен, что это когда-либо работает. Я пробовал ваш исходный код, и он никогда не работает на моей стороне.

1. Быстрое решение

В onPanEndвместо того, чтобы очищать точки, повторно инициализируйте список на новый []:

      onPanEnd: (DragEndDetails details) {
  setState(() {
    if (mode == "Line") {
      Offset lastPoint = points.last;
      points = []; // instead of points.clear();
      points.add(firstPoint);
      points.add(lastPoint);
      points.add(null);
    } else if (mode == "FreeDraw") {
      points.add(null);
    }
  });
},

Кстати, вы сделали это правильно, используя копию списка с points = List.from(points)..add(point);.

2. Дальнейшие упрощения

Вы можете немного упростить свой GestureDetector.

  • Ты firstPoint является points.first, нет необходимости хранить для этого отдельную переменную;
  • То же самое для твоего lastPoints;
  • В details из onPanUpdate уже дал вам localPosition;
  • Почему вы добавляете null в конце points?

Ваш Page становится:

      class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<Offset> points = <Offset>[];
  String mode = 'Line';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onPanDown: (DragDownDetails details) => setState(() => points = []),
        onPanUpdate: (DragUpdateDetails details) =>
            setState(() => points = [...points, details.localPosition]),
        onPanEnd: (DragEndDetails details) => setState(() {
          if (mode == "Line") points = [points.first, points.last];
        }),
        child: SketchArea(points: points),
      ),
    );
  }
}

Я просто изменил эту часть:

      points.add(firstPoint);
points.add(lastPoint);

к

      points = List.from(points)..add(firstPoint);
points = List.from(points)..add(lastPoint);

и моя проблема решена.

Другие вопросы по тегам