如何平移和缩放图像?

per*_*tus 8 dart flutter

我正在尝试为图像获得一些基本的平移和缩放功能。无状态版本可以显示图像(通过 Transform 旋转 180 度)并且 Scale 事件显示在日志中,但仅此而已。

是GestureDetector获取平移/捏/展开事件的正确小部件吗?我应该查看转换、动画,还是应该只修改Image小部件内的字段?

无状态版本

// Wraps an Image widget to provide pan and zoom functionality.
class InteractiveImage extends StatelessWidget {
  InteractiveImage(this._image, {Key key}) : super(key: key);

  final Image _image;

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new GestureDetector(
        onScaleStart: (ScaleStartDetails details) => print(details),
        onScaleUpdate: (ScaleUpdateDetails details) => print(details),
        onScaleEnd: (ScaleEndDetails details) => print(details),
        child: new Transform(
          transform: new Matrix4.rotationZ(math.PI),
          alignment: FractionalOffset.center,
          child: _image,
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

有状态版本(不起作用)

// Wraps an Image widget to provide pan and zoom functionality.
class InteractiveImage extends StatefulWidget {
  InteractiveImage(this._image, {Key key}) : super(key: key);

  final Image _image;

  @override
  _InteractiveImageState createState() => new _InteractiveImageState(_image);
}

class _InteractiveImageState extends State<InteractiveImage> {
  _InteractiveImageState(this._image);

  final Image _image;

  @override
  Widget build(BuildContext context) {
    setState(() => print("STATE SET\n"));
    return new GestureDetector(
      onScaleStart: (ScaleStartDetails details) => print(details),
      onScaleUpdate: (ScaleUpdateDetails details) => print(details),
      onScaleEnd: (ScaleEndDetails details) => print(details),
      child: new Transform(
        transform: new Matrix4.rotationZ(math.PI),
        alignment: FractionalOffset.center,
        child: _image,
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

更新(库解决方案)

使用https://pub.dartlang.org/packages/zoomable_image

(也许可以帮我添加物理和弹性边缘?)

Cop*_*oad 30

您可以使用随 Flutter 开箱即用的InteractiveViewer。

@override
Widget build(BuildContext context) {
  return Center(
    child: InteractiveViewer(
      panEnabled: false, // Set it to false
      boundaryMargin: EdgeInsets.all(100),
      minScale: 0.5,
      maxScale: 2,
      child: Image.asset(
        'your_image_asset',
        width: 200,
        height: 200,
        fit: BoxFit.cover,
      ),
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)

  • @PeterWauyo 太棒了,但是放大后,我无法用单指向右或向左移动图像,我必须用两根手指来移动? (2认同)

Col*_*son 6

我不确定你所说的“不起作用”是什么意思,但你走在正确的轨道上。

查看https://github.com/flutter/flutter/blob/master/examples/layers/widgets/gestures.dart以获得可以平移、捏合和缩放的小部件的工作示例。


dav*_*ola 6

根据问题中的代码并受到科林答案的鼓励,这就是我想到的:

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart';

class InteractiveImage extends StatefulWidget {
  InteractiveImage(this.image, {Key key}) : super(key: key);

  final Image image;

  @override
  _InteractiveImageState createState() => new _InteractiveImageState();
}

class _InteractiveImageState extends State<InteractiveImage> {
  _InteractiveImageState();

  double _scale = 1.0;
  double _previousScale = null;

  @override
  Widget build(BuildContext context) {
    setState(() => print("STATE SET\n"));
    return new GestureDetector(
      onScaleStart: (ScaleStartDetails details) {
        print(details);
        // Does this need to go into setState, too?
        // We are only saving the scale from before the zooming started
        // for later - this does not affect the rendering...
        _previousScale = _scale;
      },
      onScaleUpdate: (ScaleUpdateDetails details) {
        print(details);
        setState(() => _scale = _previousScale * details.scale);
      },
      onScaleEnd: (ScaleEndDetails details) {
        print(details);
        // See comment above
        _previousScale = null;
      },
      child: new Transform(
        transform: new Matrix4.diagonal3(new Vector3(_scale, _scale, _scale)),
        alignment: FractionalOffset.center,
        child: widget.image,
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然它似乎有效,但如果能得到 Flutter 团队内部人员的确认或纠正那就太好了。

(此外,这仅允许缩放。未实现平移。)

编辑:编辑以反映科林的评论和他更详细的解释。但请注意,关于私有setState()和私有字段仍然存在一个悬而未决的问题,这些问题不会立即影响渲染。