即使缩放图像时也将小部件保持在相对位置

问题描述 投票:0回答:1

[几天以来,我试图在图像缩放(放大/缩小)时,在图像上保留绘制的圆圈(使用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;
  }
}

我确实做了很多尝试,但看起来我的大脑无法解决,非常欢迎您提供任何帮助。

flutter drawing scale
1个回答
0
投票

我找到了一个解决方案,使用此帮助器类,我可以计算绝对点的相对点:

  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,
        ));
  }
© www.soinside.com 2019 - 2024. All rights reserved.