【发布时间】:2020-06-27 00:08:06
【问题描述】:
我目前正在尝试使用 Flutter 编写一些您可能称之为“绘画应用程序”的东西。 目标是使用 CustomePainter 小部件和路径,在图像上绘画。我想出了那部分,如果我不缩放图像,它就可以很好地工作。但我也想让它可扩展,这样我就可以更接近图像来绘制更详细的图像。 我使用 Paths 是因为我希望能够在 Path 内部点击并获得响应(使用“Path.contains”)。
问题是,当我使用缩放时,如果缩放较小,油漆会被传送到我点击的左上角,当缩放更大时,它会被传送到我点击的右下角. 我这个我的问题只是我错误地计算了偏移量。但我想不出更好的公式。 另外,缩放后的移动/变换有问题。 如果 Scaled 对象的移动速度比手指的实际移动速度慢或快。 我设法找到了一个解决方案(通过尝试理解公式)以正确的速度移动对象,但初始位置要么在右下角,要么在左上角,具体取决于比例。
我认为我所需要的只是计算缩放的偏移量的正确公式。
另外,我注意到,手势检测器没有检测到初始区域之外的任何东西,所以如果我缩小图像,点击图像会被检测到,但图像外的手势会被忽略。 有没有办法检测屏幕上的所有手势?
我对 Flutter 和一般编程还很陌生,所以我可能会问一些非常愚蠢的问题,但不幸的是,我找不到这些问题的任何答案。
在下面的代码中,我包含了用于获取偏移量的两个替代代码。两者都有自己的优势,我很想从一个代码替代方案中获得初始定位,并从另一个代码替代方案中获得正确的运动计算......
关于代码:您可以在应用栏中按“手势”图标在移动内容和在内容上绘图之间切换,使用捏合放大和缩小,使用“垃圾箱”图标撤消绘图
//编辑:解释代码,添加网络图片并更改一个图标 //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;
}
【问题讨论】:
-
我需要一点时间来理解代码,但看起来这正是我所需要的。
-
我注意到您不支持旋转,因此您可以从我的代码中删除“旋转部分”:line 165
-
好的,因此使用此代码可以完美地进行缩放和翻译,但我无法弄清楚如何从矩阵4 中获取偏移量(抽头的位置)。编辑:是的,我只是使用了代码并将“shouldRotate”值设置为“false”。
-
“但我不知道如何从矩阵中获取偏移量(水龙头的位置)” - 抱歉,我不知道你的意思
标签: flutter transformation gesturedetector