Виджет Flutter не перестраивается при обновлении состояния

Я пытаюсь создать приложение, в котором вы можете рисовать стилусом на изображениях.

я использую Listenerwidget для прослушивания ввода стилуса для сохранения смещений в переменной для их рисования на холсте с помощью CustomPainter. Я также могу стереть штрихи, которые я сделал в eraserMode = trueстилусом, удаляя точки из списка. Поверх Listener у меня есть InteractiveViewerвиджет для увеличения изображения. Но тут возникает проблема. Всякий раз, когда я устанавливал в ÌnteractiveViewerк false, чтобы стилус не двигал изображение, виджет не ребилдится, когда убираю смещения из списка. Он перестраивается только после того, как я переключу eraserModeк ложному. Рисунок по-прежнему работает, как задумано. Если panEnabledустановлено значение true, удаление точек работает мгновенно, но затем перо также перемещает изображение.

Код выглядит так

      import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'utils.dart';
import 'workSheetDrawer.dart';
import 'pdf_image_info.dart';

class DigitalInkView extends StatefulWidget {
  const DigitalInkView({Key? key, required this.image, required this.pages})
      : super(key: key);

  final ui.Image image;
  final int pages;

  @override
  _DigitalInkViewState createState() => _DigitalInkViewState();
}

class _DigitalInkViewState extends State<DigitalInkView> {
  List<Offset?> _points = <Offset>[];
  Offset _offset = const Offset(0, 0);
  bool eraserMode = false;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // Init PDFImageInfo object
    PDFImageInfo imageInfo = PDFImageInfo(
        image: widget.image, context: context, pages: widget.pages);

    Listener listener = Listener(
        onPointerMove: _updatePoints,
        onPointerUp: _addNull,
        child: CustomPaint(
            size: Size.infinite,
            painter: WorkSheetDrawer(
                points: _points,
                markerPoints: _markerPoints,
                imageInfo: imageInfo,
                offset: _offset,
                markerMode: markerMode)));

    return Scaffold(
      appBar: AppBar(
        title: const Text('Handschrift Erkennung'),
        toolbarHeight: 56,
      ),
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
                child: InteractiveViewer(
                    boundaryMargin: const EdgeInsets.all(0.0),
                    minScale: 1.01,
                    maxScale: 3.0,
                    panEnabled: false,  //When this is set to true erasing works.
                                        //When set to false, the widget only rebuilds
                                        //after setting eraserMode to false
                    scaleEnabled: true,
                    child: listener)),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  ElevatedButton(
                    child: const Text('Eraser Mode'),
                    style: _getEraserButtonColor(),
                    onPressed: _setEraserMode,
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _updatePoints(PointerEvent details) {
    setState(() {
      // Normal write mode
      if (details.kind == ui.PointerDeviceKind.stylus &&
          eraserMode == false) {
        _points = List.from(_points)..add(details.localPosition);
      }
      // Eraser mode
      else if (details.kind == ui.PointerDeviceKind.invertedStylus ||
          (details.kind == ui.PointerDeviceKind.stylus && eraserMode == true)) {
        removePoints(details.localPosition);
      }
      } else {
        // Nur negatives offset addieren
        Offset newOffset = _offset + details.delta;
        double dy = newOffset.dy;
        if (newOffset.dy > 0) {
          dy = 0;
        }
        _offset = Offset(0, dy);
      }
    });
  }

  void removePoints(Offset offset) {
    // check if input offset is close to offsets in _points and return
    // a offset close to input offset if so
    List<Offset> closeOffsets = getClosePoint(offset, _points);
    if (closeOffsets.isNotEmpty) {
      for (var closeOffset in closeOffsets) {
        // get index where stroke starts and ends
        int startIndex = getIndexOfStroke(closeOffset, "start", _points);
        int endIndex = getIndexOfStroke(closeOffset, "end", _points);
        // remove stroke
        setState(() {
          _points.removeRange(startIndex, endIndex + 1);
        });
      }
    }
  }

  List<Offset> getClosePoint(Offset offset, List<Offset?> strokes) {
    List<Offset> closePoints = <Offset>[];
    for (var point in strokes) {
      if (point != null) {
        // calculate distance between input offset and point from _points
        // add point to list if distance is smaler than 10 (the correct radius
        // needs to be evaluated after testing)
        if ((offset - point).distance < 20) {
          closePoints.add(point);
        }
      }
    }
    return closePoints;
  }

  // Returns the first index in _points of the stroke belonging to the input
  // offset. If "end" is passed as location, the last index of the stroke is
  // returned.
  int getIndexOfStroke(Offset offset, String location, List<Offset?> strokes) {
    int index = strokes.indexOf(offset);
    Offset? point = offset;
    int inc = location == "end" ? 1 : -1;
    while (point != null) {
      index += inc;
      if (index == 0) {
        break;
      }
      point = strokes[index];
    }
    return index - inc;
  }

  void _addNull(PointerEvent details) {
      _points.add(null);
  }

  void _clearPad() {
    setState(() {
      _points.clear();
      _recognisedText = '';
      _recognisedOffsetText = '';
    });
  }

  void _setEraserMode() {
    setState(() {
        eraserMode = eraserMode ? false : true;
    });
  }

  ButtonStyle _getEraserButtonColor() {
    Color buttonColor = eraserMode ? Colors.red : Colors.blue;
    return ButtonStyle(
      backgroundColor: MaterialStateProperty.all<Color>(buttonColor),
    );
  }
}

Почему виджет восстанавливается только после того, как я снова нажму кнопку «Режим ластика»? Добавление смещений к _pointsтоже до сих пор работает.

Заранее большое спасибо!

0 ответов

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