如何使用 dart 在 flutter 中创建具有可拖动支持的自定义路由路径 ui

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

大家好,我正在开发一个 flutter 应用程序,我需要创建一个支持可拖动功能的自定义路径类型的 UI(如下图所示)。

在这里,用户应该能够在灰色路径(路线)中拖动目标标记(引脚),当用户停止拖动目标标记(引脚)时,我需要一个目标值,其中用户已更新目标并基于我需要显示用户如何完成他的目标的更新目标。

任何人都可以帮我实现这种功能吗?

flutter dart drag-and-drop draggable
1个回答
0
投票

使用以下示例图像(存储为

images/flag.png
):

您可以将

Flow
小部件与自定义
FlowDelegate
类一起使用,以您喜欢的方式绘制其子级:

class FooBar extends StatelessWidget {
  final notifier = ValueNotifier(0.0);

  @override
  Widget build(BuildContext context) {
    return Flow(
      delegate: FooBarDelegate(notifier),
      children: [
        // child 0 - moving yellow flag
        DecoratedBox(
          decoration: const BoxDecoration(
            border: Border.symmetric(horizontal: BorderSide(color: Colors.black54, width: 1)),
          ),
          child: Stack(
            children: [
              ImageFiltered(
                imageFilter: ImageFilter.blur(sigmaX: 2, sigmaY: 2),
                child: Transform.translate(
                  offset: const Offset(2, 2),
                  child: Image.asset('images/flag.png',
                    colorBlendMode: BlendMode.modulate,
                    color: Colors.black,
                  ),
                ),
              ),
              Image.asset('images/flag.png',
                colorBlendMode: BlendMode.modulate,
                color: Colors.yellow,
              ),
              Positioned.fromRect(
                rect: const Rect.fromLTWH(9, 24, 58, 40),
                child: GestureDetector(
                  onPanUpdate: (d) => notifier.value += d.delta.dy,
                  child: const Center(child: Text('drag me')),
                ),
              ),
            ],
          ),
        ),
        // children 1..N - static flags
        for (int i = 0; i < 6; i++)
          IgnorePointer(
            child: Image.asset('images/flag.png',
              color: HSVColor.fromAHSV(1, 360 * i / 6, 1, 0.66).toColor(),
              colorBlendMode: BlendMode.modulate,
            ),
          ),
      ],
    );
  }
}

class FooBarDelegate extends FlowDelegate {
  FooBarDelegate(this.notifier) : super(repaint: notifier);

  final ValueNotifier<double> notifier;
  final flagAnchor = const Offset(68, 95);

  @override
  void paintChildren(FlowPaintingContext context) {
    final r = Offset.zero & context.size;
    final flagSize = context.getChildSize(0)!;
    final h = r.height - flagSize.height;
    final t0 = notifier.value / h;
    print('t0: ${t0.toStringAsFixed(2)}');

    final p0 = Alignment.topRight.inscribe(flagSize, r).topLeft + flagAnchor;
    final p1 = Alignment.bottomLeft.inscribe(flagSize, r).topLeft + flagAnchor;
    final rect = Rect.fromPoints(p0, p1);

    final numFlags = context.childCount - 1;
    final ts = List.generate(numFlags, (i) => (i + 0.5) / numFlags);
    final index = ts.lowerBound(t0, (p0, p1) => p0.compareTo(p1));

    if (index == 0) _paintHandle(context, rect, t0);
    ts.forEachIndexed((i, t) {
      _paintStaticFlag(context, rect, t, i + 1);
      if (index == i + 1) _paintHandle(context, rect, t0);
    });
  }

  _paintStaticFlag(FlowPaintingContext context, Rect rect, double t, int child) {
    final transform = composeMatrixFromOffsets(
      anchor: flagAnchor,
      translate: Offset.lerp(rect.topRight, rect.bottomLeft, t)!,
      rotation: -pi / 32,
    );
    context.paintChild(child, transform: transform);
  }

  _paintHandle(FlowPaintingContext context, Rect rect, double t) {
    final transform = composeMatrixFromOffsets(
      anchor: flagAnchor,
      translate: Offset.lerp(rect.topRight, rect.bottomLeft, t)!,
      rotation: pi / 16,
    );
    context.paintChild(0, transform: transform);
  }

  @override
  BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) {
    return constraints.loosen();
  }

  @override
  bool shouldRepaint(covariant FlowDelegate oldDelegate) => false;
}

Matrix4 composeMatrixFromOffsets({
  double scale = 1,
  double rotation = 0,
  Offset translate = Offset.zero,
  Offset anchor = Offset.zero,
}) {
  final double c = cos(rotation) * scale;
  final double s = sin(rotation) * scale;
  final double dx = translate.dx - c * anchor.dx + s * anchor.dy;
  final double dy = translate.dy - s * anchor.dx - c * anchor.dy;
  return Matrix4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
}
© www.soinside.com 2019 - 2024. All rights reserved.