Виджет Flutter не перестраивается при обновлении состояния
Я пытаюсь создать приложение, в котором вы можете рисовать стилусом на изображениях.
я использую
Listener
widget для прослушивания ввода стилуса для сохранения смещений в переменной для их рисования на холсте с помощью 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
тоже до сих пор работает.
Заранее большое спасибо!