[几天以来,我试图在图像缩放(放大/缩小)时,在图像上保留绘制的圆圈(使用CustomPainter)。要渲染图像并启用缩放手势,请使用photo_view。只要没有缩放比例,我就可以根据视口的变化移动圆。所有值(比例,偏移)由PhotoViewController作为流提供,如下所示:
main.dart
import 'package:backtrack/markerPainter.dart';
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'dart:math' as math;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Offset position;
Offset startPosition;
Offset scaleChange;
Offset offsetToCenter;
double initialScale;
Offset forPoint;
PhotoViewScaleStateController controller;
PhotoViewController controller2;
double lastscale;
@override
void initState() {
super.initState();
controller = PhotoViewScaleStateController();
controller2 = PhotoViewController();
controller2.outputStateStream.listen((onData) {
// print("position change: " + onData.position.toString());
// print("scale change: " + onData.scale.toString());
if (position != null) {
setState(() {
final scaleToUser = initialScale + (initialScale - onData.scale);
//Change to the unscaled point inverted to reflect the opposite movement of the user
final newOffset = (offsetToCenter - onData.position) * -1;
print("new offset: " + newOffset.toString());
if (onData.scale != lastscale) {
if (onData.scale > initialScale) {
//zoom in
var zoomeChnage = initialScale-onData.scale;
scaleChange = startPosition * zoomeChnage;
print("new scaleChange: " + scaleChange.toString());
} else {
//zoom out
}
lastscale = onData.scale;
}
forPoint = newOffset-scaleChange;
print("new forPoint: " + forPoint.toString());
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildMap(context));
}
Widget _buildMap(BuildContext context) {
return Container(
child: CustomPaint(
foregroundPainter: MyPainter(position, forPoint),
child: PhotoView(
imageProvider: AssetImage("asset/map.JPG"),
onTapUp: (a, b, c) {
setState(() {
position = b.localPosition;
offsetToCenter = c.position;
forPoint = Offset.zero;
initialScale = c.scale;
print("localPosition: " + b.localPosition.toString());
print("offsetToCenter: " + offsetToCenter.toString());
print("initialScale: " + initialScale.toString());
});
},
scaleStateController: controller,
controller: controller2,
),
),
);
}
}
以防万一,下面是在图像顶部绘制圆的小部件。markerPainter.dart
class MyPainter extends CustomPainter {
final Offset position;
final Offset centerOffset;
final Paint line;
MyPainter(this.position, this.centerOffset)
: line = new Paint()
..color = Colors.pink
..style = PaintingStyle.fill
..strokeWidth = 5;
@override
void paint(Canvas canvas, Size size) {
if (position == null) {
return;
}
canvas.drawCircle(position + centerOffset, 5, line);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
我确实做了很多尝试,但看起来我的大脑无法解决,非常欢迎您提供任何帮助。
我找到了一个解决方案,使用此帮助器类,我可以计算绝对点的相对点:
FlatMapState(
{this.imageScale,
this.initialViewPort,
this.imageSize,
this.viewPortDelta,
this.viewPortOffsetToCenter,
this.currentViewPort});
Offset absolutePostionToViewPort(Offset absolutePosition) {
var relativeViewPortPosition =
((imageSize * imageScale).center(Offset.zero) -
absolutePosition * imageScale) *
-1;
relativeViewPortPosition += viewPortOffsetToCenter;
return relativeViewPortPosition + viewPortDelta / -2;
}
}
该类从如下所示的PhotoViewController更新事件中获取或多或少的所有信息:
bool _photoViewValueIsValid(PhotoViewControllerValue value) {
return value != null && value.position != null && value.scale != null;
}
FlatMapState createCurrentState(PhotoViewControllerValue photoViewValue) {
if (_photoViewValueIsValid(photoViewValue) && imageSize != null) {
if (lastViewPort == null) {
lastViewPort = stickyKey.currentContext.size;
}
return FlatMapState(
imageScale: photoViewValue.scale,
imageSize: imageSize,
initialViewPort: lastViewPort,
viewPortDelta: Offset(
lastViewPort.width - stickyKey.currentContext.size.width,
lastViewPort.height - stickyKey.currentContext.size.height),
viewPortOffsetToCenter: photoViewValue.position,
currentViewPort: Offset(stickyKey.currentContext.size.width,
stickyKey.currentContext.size.height),
);
} else {
//The map or image is still loading, the state can't be generated
return null;
}
}
请注意,必须通过这样将原点设置为中心来绘制计算值:
@override
void paint(Canvas canvas, Size size) {
//In case the state is null or nothing to draw leave
if(flatMapState == null || drawableElements == null){
return;
}
//Center the canvas (0,0) is now the center, done to have the same origion as photoview
var viewPortCenter = flatMapState.initialViewPort.center(Offset.zero);
canvas.translate(viewPortCenter.dx, viewPortCenter.dy);
drawableElements.forEach((drawable) => drawable.draw(
canvas,
size,
flatMapState,
));
}