在flutter中拖动widget时如何实现定位线?

2023-12-11

我试图在拖动时获取定位线(紫色线)。请参阅该附件以了解有关该问题的更多信息。

enter image description here


线条是用canvas.drawPoints()在 和 的paint()方法 - 您可以更改它来绘制虚线

现在,带有黑色实线,它看起来像这样:

enter image description here

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

class _FooResizerState extends State<FooResizer> with TickerProviderStateMixin, ChangeNotifier {
  Sizer currentSizer;
  double angle = 0.0;
  AnimationController ctrl;

  final Map<String, Sizer> sizers = {
    'l': Sizer('l', Alignment.centerLeft, {'t': 0.5, 'b': 0.5, 'M': 0.5}),
    't': Sizer('t', Alignment.topCenter, {'l': 0.5, 'r': 0.5, 'M': 0.5}),
    'r': Sizer('r', Alignment.centerRight, {'t': 0.5, 'b': 0.5, 'R': 1.0, 'M': 0.5}),
    'b': Sizer('b', Alignment.bottomCenter, {'l': 0.5, 'r': 0.5, 'R': 1.0, 'M': 0.5}),
    'R': Sizer('R', Alignment.bottomRight, {}),
    'M': Sizer('M', Alignment.center, {}),
  };

  @override
  void initState() {
    super.initState();
    ctrl = AnimationController(vsync: this, duration: Duration(milliseconds: 300), value: 1.0);
  }

  @override
  Widget build(BuildContext context) {
    return ClipRect(
      child: ColoredBox(
        color: Colors.black12,
        // CustomMultiChildLayoutPainter:
        // https://gist.github.com/pskink/0f82724b41d9ebe89604782fbf62fe03#file-multi_layout_painter-dart-L447
        child: CustomMultiChildLayoutPainter(
          delegate: _FooResizerDelegate(sizers, this),
          children: [
            LayoutId(
              id: 'body',
              child: AnimatedBuilder(
                animation: this,
                builder: (ctx, child) {
                  return Transform.rotate(
                    angle: angle,
                    child: child,
                  );
                },
                child: Material(color: Colors.grey[300], elevation: 4, child: FlutterLogo()),
              ),
            ),
            ...sizers.values.map(_sizerBuilder),
          ],
        ),
      ),
    );
  }

  Widget _sizerBuilder(Sizer sizer) {
    final colors = {
      'M': Colors.orange,
      'R': Colors.teal,
    };
    return LayoutId(
      id: sizer.id,
      child: GestureDetector(
        onPanStart: (details) => _panStart(sizer),
        onPanUpdate: _panUpdate,
        onPanEnd: _panEnd,
        child: AnimatedBuilder(
          animation: ctrl,
          builder: (context, child) {
            final color = colors[sizer.id] ?? Colors.green;
            return Opacity(
              opacity: currentSizer == sizer? 1.0 : Curves.ease.transform(ctrl.value),
              child: Container(
                decoration: ShapeDecoration(
                  shape: CircleBorder(side: BorderSide(width: lerpDouble(0.0, 2.0, ctrl.value), color: Colors.black38)),
                  color: currentSizer == sizer? Color.lerp(Colors.deepPurple, color, ctrl.value) : color,
                  shadows: [BoxShadow.lerp(BoxShadow(spreadRadius: 2, blurRadius: 4, offset: Offset(2, 2)), null, ctrl.value)],
                ),
              ),
            );
          }
        ),
      ),
    );
  }

  _panStart(Sizer sizer) {
    currentSizer = sizer;
    ctrl.reverse();
  }

  _panUpdate(DragUpdateDetails details) {
    assert(currentSizer != null);
    if (currentSizer.id == 'M') {
      // move
      sizers.values.forEach((sizer) => sizer.center += details.delta);
    } else
    if (currentSizer.id == 'R') {
      // rotate
      final localCenter = sizers['M'].center;
      final globalCenter = (context.findRenderObject() as RenderBox).localToGlobal(localCenter);

      final angle0 = (details.globalPosition - details.delta - globalCenter).direction;
      final angle1 = (details.globalPosition - globalCenter).direction;
      final deltaAngle = angle1 - angle0;
      sizers.values
        .where((sizer) => sizer.id != 'M')
        .forEach((sizer) {
          final vector = sizer.center - localCenter;
          sizer.center = localCenter + Offset.fromDirection(vector.direction + deltaAngle, vector.distance);
        });
      angle += deltaAngle;
    } else {
      // resize
      final adjustedAngle = angle + currentSizer.angleAdjustment;
      final rotatedDistance = details.delta.distance * math.cos(details.delta.direction - adjustedAngle);
      final vector = Offset.fromDirection(adjustedAngle, rotatedDistance);
      currentSizer.center += vector;
      currentSizer.dependents.forEach((id, factor) => sizers[id].center += vector * factor);
    }
    notifyListeners();
  }

  _panEnd(DragEndDetails details) {
    assert(currentSizer != null);
    // currentSizer = null;
    ctrl.forward();
  }
}


class _FooResizerDelegate extends MultiChildLayoutPainterDelegate {
  static const SIZE = 48.0;
  final Map<String, Sizer> sizers;

  _FooResizerDelegate(this.sizers, Listenable relayout) : super(relayout: relayout);

  @override
  void performLayout(Size size) {
    sizers['M'].center ??= init(size);

    for (var sizer in sizers.values) {
      layoutChild(sizer.id, BoxConstraints.tight(Size(SIZE, SIZE)));
      positionChild(sizer.id, sizer.center - Offset(SIZE / 2, SIZE / 2));
    }
    final w = (sizers['l'].center - sizers['r'].center).distance;
    final h = (sizers['t'].center - sizers['b'].center).distance;
    layoutChild('body', BoxConstraints.tight(Size(w, h)));
    positionChild('body', sizers['M'].center - Offset(w / 2, h / 2));
  }

  Offset init(Size size) {
    final rect = (Offset.zero & size).deflate(24);
    print('init rect: $rect');
    for (var sizer in sizers.values) {
      sizer
        ..center = sizer.alignment.withinRect(rect)
        ..angleAdjustment = sizer.alignment.x == 0? math.pi / 2 : 0;
    }
    return sizers['M'].center;
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;

  @override
  void foregroundPaint(Canvas canvas, Size size) {
  }

  @override
  void paint(Canvas canvas, Size size) {
    final w = (sizers['r'].center - sizers['l'].center).distance;
    final h = (sizers['b'].center - sizers['t'].center).distance;
    final rect = Rect.fromCenter(center: sizers['M'].center, width: w, height: h);
    final angle = (sizers['r'].center - sizers['l'].center).direction;
    final matrix = Matrix4.identity()
      ..translate(rect.center.dx, rect.center.dy)
      ..rotateZ(angle)
      ..translate(-rect.center.dx, -rect.center.dy);
    final transformedRect = MatrixUtils.transformRect(matrix, rect);
    final points = [
      Offset(transformedRect.left, 0), Offset(transformedRect.left, size.height),
      Offset(0, transformedRect.top), Offset(size.width, transformedRect.top),
      Offset(transformedRect.right, 0), Offset(transformedRect.right, size.height),
      Offset(0, transformedRect.bottom), Offset(size.width, transformedRect.bottom),
    ];
    canvas.drawPoints(PointMode.lines, points, Paint());
  }
}

class Sizer {
  final String id;
  final Alignment alignment;
  final Map<String, double> dependents;
  Offset center;
  double angleAdjustment;
  Sizer(this.id, this.alignment, this.dependents);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在flutter中拖动widget时如何实现定位线? 的相关文章

  • Python Selenium:如何在文本文件中打印网站上的值?

    我正在尝试编写一个脚本 该脚本将从 tulsaspca org 网站获取以下 6 个值并将其打印在 txt 文件中 最终输出应该是 905 4896 7105 23194 1004 42000 放置的动物 的 HTML span class
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写
  • 如何在发布期间复制未版本化的测试资源:执行?

    我的问题与 Maven 在发布时不会复制未跟踪的资源 https stackoverflow com questions 10378708 maven doesnt copy untracked resources while releas
  • CFdump cfcomponent cfscript

    可以在 cfcomponent 中使用 cfdump 吗 可以在 cfscript 中使用 cfdump 吗 我知道 anser 不是 那么如何发出 insde cfcomponent 函数的值 cf脚本 我用的是CF8 可以在 cfcom
  • 如何确定所有角度2分量都已渲染?

    当所有 Angular2 组件完成渲染时 是否会触发一个角度事件 For jQuery 我们可以用 function 然而 对于 Angular2 当domready事件被触发 html 只包含角度组件标签 每个组件完成渲染后 domrea
  • TIFF 元数据的最大大小是多少?

    TIFF 文件元数据的单个字段中可以合并的元数据数量是否有最大限制 我想在 ImageDescription 字段中存储大文本 最多几 MB 没有具体的最大限制ImageDescription但是 整个 TIFF 文件存在最大文件大小 该最
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低
  • Redis如何存储关联数组?设置、散列还是列表?

    我对 Redis 的所有可用存储选项有点困惑 我想做一些简单的事情 并且不想过度设计它 我正在与phpredis and Redis v2 8 6 我有一个需要存储的简单关联数组 我还需要能够通过其键检索项目并循环遍历所有项目 a arra
  • PHPUnit 和 Zend Framework assertRedirectTo() 问题

    我在创建的测试中遇到了 assertRedirectTo 问题 下面是我使用的代码 public function testLoggedInIndexAction this gt dispatch this gt assertControl
  • 从超立方体图像中获取文本的确切位置

    使用 tesseract 中的 GetHOCRText 0 方法 我能够检索 html 中的文本 并在 webview 中呈现 html 时 我能够获取文本 但图像中文本的位置与输出不同 任何想法都非常有帮助 tesseract gt Se
  • CSS溢出文本显示在几行中,没有断字

    我有一些长文本显示在 div 中 该 div 具有固定的宽度和高度 我希望文本显示在几行上 作为 div 高度 并且句子单词不会中断 一行中的单词前缀和下一行中的继续 此外 我想在末尾添加省略号最后一句话 CSS white space n
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个
  • rspec 中的模拟方法链

    有一系列方法可以获得user目的 我试图模拟以下内容以返回user in my Factory Girl current user AuthorizeApiRequest call request headers result 我可以模拟该
  • 使用 xpath 和 vtd-xml 以字符串形式获取元素的子节点和文本

    这是我的 XML 的一部分
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip
  • Erlang dict的时间复杂度

    我想知道 Erlang OTP 是否dict模块是作为哈希表实现的 在这种情况下它是否能提供这样的性能 平均情况 Search O 1 n k Insert O 1 Delete O 1 n k 最坏的情况下 Search O n Inse
  • 升级到 Rails 6 时是否有一种编程方法可以检测 Zeitwerk::NameError?

    我目前正在将旧的 Rails 应用程序迁移到 Rails 6 好像项目中有些文件和里面定义的类不一致 运行应用程序测试时我没有看到此错误 但部署后我收到如下错误 Zeitwerk NameError expected file app my
  • 在 Nexus 7 2013 上更改方向时 CSS 媒体查询不起作用

    我目前正在我的笔记本电脑 台式电脑和 Nexus 7 2013 上测试 CSS 媒体查询 除了 Nexus 7 之外 它们在台式机和笔记本电脑上都运行良好 当我更改方向时 除非刷新页面 否则样式不会应用 例如 以纵向模式握住设备时 页面正常
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • 如果检测到匹配的文件,则运行 pre-commit.com 挂钩一次(并非针对每个文件)

    我有一个钩子 可以从源文件生成文档文件 使用pre commit com 框架 在该挂钩中调用的函数没有文件参数 因此它只是为目录中的所有源文件创建文档 钩子是一个systemhook 即只是一个 bash 脚本 我在其中调用该函数来创建文
  • matplotlib qt imshow animate [重复]

    这个问题在这里已经有答案了 imshow 动画可以与 qt 后端一起使用吗 以下在非 qt 中工作正常 但不使用 qt 制作动画 只显示最后一帧 img standard normal 40 40 image imshow img inte
  • 最好的自动换行算法? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 自动换行是现代文本编辑器的必备功能之一 如何处理自动换行 最好的自动换行算法是什么 如果文本有几百万行 如何才能快速自动换行 为什么我需要解决方案 因为我的项目必须绘制具有各种缩放级别的文
  • 根据容器宽度动态调整文本大小

    我正在研究响应式设计 并且有一些显示 h3 当浏览器窗口宽度减小时 我想缩小的标签 初始设置 基于 960px 宽度 正文字体大小设置为 14px h3标签的字体大小为40px 包含div的宽度为230px 这是我为 javascript
  • 如何在 Google Drive Api v3 中进行部分下载?

    文档说here您需要使用 Range 标头Range bytes 500 999 My code def downloadChunkFromFile file id start length headers Range bytes form
  • 以同样的方式打乱多个 javascript 数组

    我有两个数组 var mp3 sing mp3 song mp3 tune mp3 jam mp3 etc var ogg sing ogg song ogg tune ogg jam ogg etc 我需要对两个数组进行洗牌 以便它们以相
  • 检索 AngularJS 应用程序名称

    如何在 AngularJS 中检索当前应用程序的名称 我的意思是ng app foo value 我搜索了 API 文档 但找不到任何对此的参考 我的解决方案实际上我已经找到了这样的解决方案 angular element ng app a
  • 有没有办法在一定的空闲时间后将 GKE 集群的大小调整为 0 个节点?

    我有一个 GKE 集群 我希望它位于 0 个节点 扩展到 3 个节点来执行任务 然后在一定的空闲时间后 缩小到 0 个节点 有没有办法做到这一点 由于集群中运行着系统 Pod GKE 集群永远无法缩小到 0 在 kube system 命名
  • 按多个属性对 js 对象进行分组

    在下面的示例中 我有一个对象数组 我按其属性中的 2 个对它们进行分组 基于https stackoverflow com a 40142591 var arr id 1 tags main yearCode 2018 id 2 tags
  • 如何键入深度嵌套的字典和列表结构[重复]

    这个问题在这里已经有答案了 在给定的 d d1 1 2 d2 this is tricky tough 1 2 me 问题要求我打印 me 我试图理解字典中给定的键和值来查找基于该键的任何关系 但无法这样做 在进一步潜水之前是否应该了解某些
  • 证明内容 flex-end 不适用于 IE

    Flex end适用于chrome和firefox 但不适用于ie 请执行以下代码 flex container display flex flex wrap nowrap background color DodgerBlue flex
  • 如何使用 JavaScript 和 PHP 将画布图像保存到服务器?

    我正在努力使用 JavaScript 和 PHP 将画布图像保存到服务器 我已经尝试了 JS 和 PHP 的多个示例 但总是失败 关于如何将图像数据发送到 PHP 脚本 base64 blob FormData 的建议存在冲突 并且我不确定
  • 简单的 Html DOM 缓存

    我正在使用 Simple HTML DOM 来抓取 经许可 一些网站 我基本上抓取了大约 50 个不同网站的统计数据 这些数据每天更新大约四次 正如您可以想象的那样 进行抓取需要时间 因此我需要通过进行一些缓存来加快该过程 我的愿景是 DA
  • 使用相当于 AutoFixture 'With' 的匿名值进行广义 Func 包装

    在基于 AutoFixture 的测试中 我尝试尽可能清晰地表达以下内容 当我经过时
  • jquery根据选择值填充表中的文本输入

    我有一个表单 其中包含一个名为 Client ID 的选择以及一些其他文本输入 我需要的是 当用户选择 Client ID 时 我的字段 Address1 Address 2 等应该填充数据库查询的结果 如下所示 SELECT Addres
  • 拟合回归曲面的 3D 图

    我正在尝试制作 3D 图表来绘制拟合回归曲面 我见过以下例子 使用 Matplotlib 在 3d 中绘制线性模型 将散点图与曲面图相结合 3 维数据的最佳拟合曲面 然而 第一个非常过时 不再工作 第二个是相关的 但我在生成值时遇到了一些麻
  • swift 中的 kCGImageAlphaNone 未解析的标识符

    我正在尝试使用 Swift 中的 CoreImage 将图像 纹理 对于 SpriteKit 转换为灰度 我找到了这个答案 https stackoverflow com a 17218546 836501我尝试将其转换为适用于 iOS7
  • 如何从 ASPX.VB 函数内部调用 ASSX?

    我需要从我用 ASHX 制作的 API 中获取一个值 通常它是从 javascript 调用的 但我需要在 ASP NET 中正确调用它 我认为这应该不是问题 但我不确定语法 那么你有几个选择 您可以将 ASHX 中的代码重构为共享库中的代
  • 从 SQL Server 的 XML 执行计划中提取数据

    我的最终目标是从缓存的执行计划中自动提取所有引用的列 这将帮助我们跟踪我们计划的 SSRS 报告集使用的所有列 感兴趣的 XML 数据如下所示
  • 在flutter中拖动widget时如何实现定位线?

    我试图在拖动时获取定位线 紫色线 请参阅该附件以了解有关该问题的更多信息 线条是用canvas drawPoints 在 和 的paint 方法 您可以更改它来绘制虚线 现在 带有黑色实线 它看起来像这样 class FooResizer