В настоящее время я пытаюсь запрограммировать что-то, что вы можете назвать «приложением рисования», используя Flutter. Цель состоит в том, чтобы использовать виджет CustomePainter и пути, чтобы рисовать на изображение. Я понял эту часть, и она работает достаточно хорошо, если я не масштабирую изображение. Но я также хочу сделать его масштабируемым, чтобы приблизиться к изображению, чтобы рисовать более подробно. Я использую Paths, потому что я хочу сделать возможным нажатие внутри Path и получение ответа (используя 'Path.contains').
Проблема, когда я использую масштабирование, состоит в том, что если масштаб меньше, краска доставляется в верхнем левом углу там, где я касаюсь, и когда масштаб больше, она доставляется в нижнем правом углу там, где я касаюсь. В этом моя проблема только в том, что я просчитал смещения. Но я не мог найти лучшую формулу. Также у меня проблема с движением / трансформацией после масштабирования. Если масштабированный объект движется медленнее или быстрее, чем фактическое движение пальца. Мне удалось найти решение (пытаясь понять формулу), которое перемещает объект с правильной скоростью, но начальная позиция - либо внизу справа, либо вверху слева, в зависимости от масштаба.
Я думаю все, что мне нужно, это правильная формула для смещения, которое учитывает масштабирование.
Кроме того, я заметил, что детектор жестов не обнаруживает ничего за пределами начальной области, поэтому, если я уменьшу изображение, нажмите на изображение обнаруживается, но жесты вне изображения игнорируются. Есть ли способ обнаружить все жесты на экране?
Я довольно плохо знаком с Флаттером и программированием в целом, поэтому я мог бы задавать действительно глупые вопросы, но я, к сожалению, не мог найти ответы на эти вопросы. эти проблемы.
В приведенный ниже код я включил оба альтернативных кода, которые я использовал для получения смещения. Оба имеют свои привилегии, и я хотел бы получить начальное позиционирование из одной альтернативы кода и правильное вычисление движения из другой ...
О коде: вы нажимаете значок «жест» в приложении панель для переключения между перемещением содержимого и рисованием содержимого, используйте масштабирование для увеличения и уменьшения масштаба и значок «tra sh» для отмены чертежа
// edit: объяснение кода, добавление сетевого изображения и изменить один значок // edit1: изменить заголовок
import 'dart:ui';
import 'package:flutter/material.dart';
class GesturePaint extends StatefulWidget {
@override
_GesturePaintState createState() => _GesturePaintState();
}
class _GesturePaintState extends State<GesturePaint> {
List<Offset> points = List();
Offset _startLastOffset = Offset.zero;
Offset _lastOffset = Offset.zero;
Offset _currentOffset = Offset.zero;
double _lastScale = 1.0;
double _currentScale = 1.0;
bool _drawable = true;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('painting app'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.gesture),
onPressed: (){
setState(() {
_drawable = _drawable ? false : true;
});
print(_drawable);
},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: (){
setState(() {
points.clear();
});
},
),
],
),
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context){
return GestureDetector(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
_transformMatrix4Image(),
//_transformScaleAndTranslate(),
_transformMatrix4(),
],
),
onScaleStart: _onScaleStart,
onScaleUpdate: _onScaleUpdate,
);
}
void _onScaleStart(ScaleStartDetails details) {
print('ScaleStartDetails: $details');
if(_drawable){
setState(() {
points.add((details.localFocalPoint/_currentScale).translate(-_currentOffset.dx,-_currentOffset.dy));
});
} else{
_lastScale = _currentScale;
_lastOffset = _currentOffset;
_startLastOffset = details.focalPoint;
}
}
void _onScaleUpdate(ScaleUpdateDetails details) {
print('ScaleUpdateDetails: $details - Scale: ${details.scale}');
if (details.scale != 1){
double currentScale = _lastScale * details.scale;
setState(() {
_currentScale = currentScale;
});
print('_scale: $_currentScale - _lastScale: $_lastScale');
} else if(details.scale == 1.0 ) {
// Calculate offset depending on current Image scaling.
if(_drawable){
//draw instead
setState(() {
// this does generally not work, i also tried to use FocalPoint, which doesn't work either,
// and i tried to use (details.localFocalPoint).tranlate, which also didn't work well
//the following is the closest i come to the initial movement, but the offset is off depending on the scale
points.add((details.localFocalPoint/_lastScale).translate(-_currentOffset.dx,-_currentOffset.dy));
});
} else{
Offset offsetAdjustedForScale = (_startLastOffset -_lastOffset )/ _lastScale;
//initial offset correct, but moves at different speeds than finger movement with following code:
//Offset currentOffset = details.focalPoint - offsetAdjustedForScale*_lastScale;
//initial offset wrong, but moves with correct speed
Offset currentOffset = details.focalPoint/_lastScale - offsetAdjustedForScale*_lastScale;
setState(() {
_currentOffset = currentOffset;
});
}
}
}
Transform _transformMatrix4(){
Matrix4 _mat = Matrix4.identity()
..scale(_currentScale,_currentScale)
..translate(_currentOffset.dx,_currentOffset.dy);
return Transform(
transform: _mat,
alignment: FractionalOffset.center,
child: PathExample(pointsList: points),
);
}
Transform _transformMatrix4Image(){
Matrix4 _mat = Matrix4.identity()
..scale(_currentScale,_currentScale)
..translate(_currentOffset.dx,_currentOffset.dy);
return Transform(
transform: _mat,
alignment: FractionalOffset.center,
child: Image(
image: NetworkImage('https://png2.kisspng.com/sh/dde5d7f3f60acef81f7e019f4f65cafb/L0KzQYm3VcA1N6Vxj5H0aYP2gLBuTfJtfZYygtNELX3yhbB7gflvNZNxjddraYLnPcjwjvcuPZJqe9ZqZkS5QIi6VcAvPmIAUKoEOEm0RYO8VMcyQWk9S6sAMT7zfri=/kisspng-blue-jay-mountain-bluebird-wing-5aecdaf4607350.6198898915254719883951.png'),
fit: BoxFit.cover,
),
);
}
}
class PathExample extends StatelessWidget {
PathExample({this.pointsList});
List<Offset> pointsList;
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: PathPainter(pointsList: pointsList),
);
}
}
class PathPainter extends CustomPainter {
PathPainter({this.pointsList});
List<Offset> pointsList;
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8;
for (int i = 0; i < pointsList.length - 1; i++) {
Path path = Path();
if(pointsList[i] != null) path.moveTo(pointsList[i].dx, pointsList[i].dy);
for(int j = i; j < pointsList.length - 1; j++ ){
if (pointsList[j] != null ) {
path.lineTo(pointsList[j].dx, pointsList[j].dy);
} if(pointsList[j] == null){
}
i = j;
}
canvas.drawPath(path, paint);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}