在 flutter 中调整旋转容器的大小

2023-12-11

我有以下代码:

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:vector_math/vector_math.dart' as vector;
import 'dart:math' as math;

void main() {
  debugPaintSizeEnabled = true;
  return runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.grey,
        body: SafeArea(
          child: TestComp(),
        ),
      ),
    );
  }
}

class TestComp extends StatefulWidget {
  @override
  _TestCompState createState() => _TestCompState();
}

class _TestCompState extends State<TestComp> {
  double _y = 0;
  double _x = 0;

  double _height = 200;
  double _width = 300;

  int angle = -136;

  vector.Vector4 testRotation(var dx, var dy) {
    vector.Matrix4 matrix = vector.Matrix4.identity();
    matrix..rotateZ(math.pi / 180 * angle);
    return matrix * vector.Vector4(dx, dy, 0, 0);
  }

  double get _aspectRatio {
    return _height / _width;
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          top: _y,
          left: _x,
          child: Transform.rotate(
            angle: math.pi / 180 * angle, //-136,
            child: Container(
              height: _height,
              width: _width,
              color: Colors.black,
              child: Stack(
                overflow: Overflow.visible,
                children: <Widget>[
                  Positioned(
                    top: 0,
                    left: 0,
                    child: GestureDetector(
                      onPanUpdate: (details) {
                        var newdx =
                            testRotation(details.delta.dx, details.delta.dy)[0];
                        var newdy =
                            testRotation(details.delta.dx, details.delta.dy)[1];
                        setState(() {
                          _y += newdy;
                          _x += newdx;
                        });
                      },
                      child: Image.network(
                        "https://via.placeholder.com/300x200",
                        height: _height,
                        width: _width,
                        fit: BoxFit.fill,
                      ),
                    ),
                  ),
                  Positioned(
                    top: 0,
                    left: 0,
                    child: GestureDetector(
                      onPanUpdate: (DragUpdateDetails details) {
                        var position = testRotation(
                          details.delta.dx,
                          details.delta.dy,
                        );
                        // print(position);
                        var dx = position[0];
                        var dy = position[1];

                        var newWidth = _width - dx;
                        var newHeight = newWidth * _aspectRatio;
                        setState(() {
                          _y = _y + (_height - newHeight);
                          _x = _x + dx;
                          _width = newWidth;
                          _height = newHeight;
                        });
                      },
                      child: Container(
                        width: 10,
                        height: 10,
                        decoration: BoxDecoration(
                          color: Colors.blue,
                          borderRadius: BorderRadius.circular(10),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
}

图像左上角有一个手柄,可用于调整大小。我希望轮换是这样的:

enter image description here

但事实并非如此。调整大小混乱了。请帮助我。


尝试这个FooResizer小部件 - 您可以用相同的方式添加 4 个额外的角大小调整器:

final SIZE = 64.0;
final sizerSize = Size.square(SIZE);

final sizers = [
  Sizer(Alignment.centerLeft, EdgeInsets.only(left: 1), Offset(1, 0)),
  Sizer(Alignment.topCenter, EdgeInsets.only(top: 1), Offset(0, 1)),
  Sizer(Alignment.centerRight, EdgeInsets.only(right: 1), Offset(-1, 0)),
  Sizer(Alignment.bottomCenter, EdgeInsets.only(bottom: 1), Offset(0, -1)),
];

class Sizer {
  final Alignment alignment;
  final EdgeInsets insets;
  final Offset mask;
  Sizer(this.alignment, this.insets, this.mask);
}

class FooResizer extends StatefulWidget {
  @override
  _FooResizerState createState() => _FooResizerState();
}

class _FooResizerState extends State<FooResizer> with TickerProviderStateMixin {
  ValueNotifier<Rect> rect;
  ValueNotifier<int> serial = ValueNotifier<int>(0);
  Sizer currentSizer;
  Rect savedRect;
  Offset savedOffset;
  AnimationController controller;
  GlobalKey stackKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    controller ??= AnimationController(vsync: this, duration: Duration(milliseconds: 300));
    return LayoutBuilder(
      builder: (context, constraints) {
        _init(constraints.biggest);
        return AnimatedBuilder(
          animation: Listenable.merge([rect, serial, controller]),
          builder: (context, child) {
            return Transform.rotate(
              angle: math.pi / 8,
              child: Stack(
                key: stackKey,
                overflow: Overflow.visible,
                children: [
                  Positioned.fromRect(
                    rect: rect.value,
                    child: Material(
                      borderRadius: BorderRadius.circular(12),
                      color: Colors.grey[300],
                      elevation: 4,
                      child: FlutterLogo(),
                    ),
                  ),
                  ...sizers.map(_sizerBuilder),
                ],
              ),
            );
          },
        );
      },
    );
  }

  Widget _sizerBuilder(Sizer sizer) {
    var isCurrent = currentSizer == sizer;
    var finalRect = sizer.alignment.inscribe(sizerSize, rect.value).shift(sizer.mask * SIZE * -0.33);
    var centerRect = Alignment.center.inscribe(sizerSize, rect.value);
    var interpolated = Rect.lerp(finalRect, centerRect, isCurrent? 0 : controller.value);
    return Positioned.fromRect(
      rect: interpolated,
      child: GestureDetector(
        onPanStart: (details) => _panStart(sizer, details),
        onPanUpdate: _panUpdate,
        onPanEnd: _panEnd,
        child: Opacity(
          opacity: isCurrent? 1 : 1 - controller.value,
          child: AnimatedContainer(
            duration: isCurrent? Duration(milliseconds: 500) : Duration.zero,
            decoration: ShapeDecoration(
              shape: isCurrent? RoundedRectangleBorder() : CircleBorder(),
              color: isCurrent? Colors.orange[800] : Colors.green,
            ),
          ),
        ),
      ),
    );
  }

  _panStart(Sizer sizer, DragStartDetails details) {
    // timeDilation = 10;
    currentSizer = sizer;
    savedRect = rect.value;
    savedOffset = _invertedOffset(details.globalPosition);
    serial.value++;
    controller.forward();
  }

  _panUpdate(DragUpdateDetails details) {
    assert(currentSizer != null);
    var delta = savedOffset - _invertedOffset(details.globalPosition);
    var insets = EdgeInsets.fromLTRB(
      currentSizer.insets.left * delta.dx * currentSizer.mask.dx,
      currentSizer.insets.top * delta.dy * currentSizer.mask.dy,
      currentSizer.insets.right * delta.dx * currentSizer.mask.dx,
      currentSizer.insets.bottom * delta.dy * currentSizer.mask.dy,
    );
    rect.value = insets.inflateRect(savedRect);
  }

  _panEnd(DragEndDetails details) {
    assert(currentSizer != null);
    currentSizer = null;
    serial.value++;
    controller.reverse();
  }

  Offset _invertedOffset(Offset offset) {
    RenderBox rb = stackKey.currentContext.findRenderObject();
    return rb.globalToLocal(offset);
  }

  void _init(Size size) {
    var r = Offset.zero & size;
    rect = ValueNotifier(r.deflate(100));
  }
}

结果会是这样的:

enter image description here

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 flutter 中调整旋转容器的大小 的相关文章