Flutter:如何为任何容器实现旋转和平移/移动手势?

Ank*_*ash 3 rotation gesture-recognition scale pan flutter

我已经为容器实现了缩放手势。另外,我添加了 onHorizo​​ntalDragUpdate 和 onVerticalDragUpdate。但是当我尝试添加两者时,我收到一个异常,说无法使用 Scale 手势实现两者。即使对于平移手势,它也会抛出相同的异常。下面是我的代码:

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' hide Colors;
 import 'dart: math' as math;

class HomeScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return HomeState();
  }
}

class HomeState extends State<HomeScreen> {

  double _scale = 1.0;
  double _previousScale;
  var yOffset = 400.0;
  var xOffset = 50.0;
  var rotation = 0.0;
  var lastRotation = 0.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.amber,
      body: Stack(
        children: <Widget>[
          stackContainer(),
        ],
      ),
    );
  }

  Widget stackContainer() {

        return Stack(
          children: <Widget>[
            Positioned.fromRect(
              rect: Rect.fromPoints( Offset(xOffset, yOffset),
                  Offset(xOffset+250.0, yOffset+100.0)),
              child: GestureDetector(
                onScaleStart: (scaleDetails) {
                  _previousScale = _scale;
                  print(' scaleStarts = ${scaleDetails.focalPoint}');
                },
                onScaleUpdate: (scaleUpdates){
                  //ScaleUpdateDetails
                  rotation += lastRotation - scaleUpdates.rotation;
                  lastRotation = scaleUpdates.rotation;
                  print("lastRotation = $lastRotation");
                  print(' scaleUpdates = ${scaleUpdates.scale} rotation = ${scaleUpdates.rotation}');
                  setState(() => _scale = _previousScale * scaleUpdates.scale);
                },
                onScaleEnd: (scaleEndDetails) {
                  _previousScale = null;
                  print(' scaleEnds = ${scaleEndDetails.velocity}');
                },
                child:
                Transform(
                  transform: Matrix4.diagonal3( Vector3(_scale, _scale, _scale))..rotateZ(rotation * math.pi/180.0),
              alignment: FractionalOffset.center,
              child: Container(
                color: Colors.red,
              ),
            )
            ,
          ),
        ),
      ],
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我想围绕红色子视图移动并随着比例旋转。

use*_*613 17

scale相关事件中,您可以使用focalPoint相关事件中,除了缩放(缩放)之外,还可以支持缩放时平移。

演示:

平移和缩放演示

以下是上述演示中使用的代码:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ZoomAndPanDemo(),
    );
  }
}

class ZoomAndPanDemo extends StatefulWidget {
  @override
  _ZoomAndPanDemoState createState() => _ZoomAndPanDemoState();
}

class _ZoomAndPanDemoState extends State<ZoomAndPanDemo> {
  Offset _offset = Offset.zero;
  Offset _initialFocalPoint = Offset.zero;
  Offset _sessionOffset = Offset.zero;

  double _scale = 1.0;
  double _initialScale = 1.0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onScaleStart: (details) {
        _initialFocalPoint = details.focalPoint;
        _initialScale = _scale;
      },
      onScaleUpdate: (details) {
        setState(() {
          _sessionOffset = details.focalPoint - _initialFocalPoint;
          _scale = _initialScale * details.scale;
        });
      },
      onScaleEnd: (details) {
        setState(() {
          _offset += _sessionOffset;
          _sessionOffset = Offset.zero;
        });
      },
      child: Transform.translate(
        offset: _offset + _sessionOffset,
        child: Transform.scale(
          scale: _scale,
          child: FlutterLogo(),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

旁注:即使发生类似的事件onHorizontalDragUpdate比例相关事件一起使用时不会导致运行时异常,但它们仍然会导致冲突并导致较差的用户体验。

还值得注意的是,InteractiveViewer内置的 Flutter 小部件可以满足您的大部分需求,因此您可能根本不需要使用GestureDetectorand 。Transform


Ank*_*ash 6

我们可以使用 ScaleUpdateDetails 对象的 focusPoint 字段,我们将其作为 onScaleUpdate 函数中的参数。

与上述例子相关的解决方案:我们需要更新 onScaleUpdate 方法。

onScaleUpdate: (scaleUpdates) {

      lastRotation += scaleUpdates.rotation;
      var offset = scaleUpdates.focalPoint;
      xOffset = offset.dx;
      yOffset = offset.dy;

      setState(() => _scale = _previousScale * scaleUpdates.scale);
    }
Run Code Online (Sandbox Code Playgroud)

在上面的代码中更改 Positioned Widget 的 'rect' 字段。

rect: Rect.fromPoints(Offset(xOffset - 125.0, yOffset - 50.0),
              Offset(xOffset + 250.0, yOffset + 100.0))
Run Code Online (Sandbox Code Playgroud)