如何在 SwiftUI 中使一条线跟随 CGPoint?

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

我创建了两个 CGPoint 以及它们之间的连接线。我的目标如下:当我使用 SwiftUI DragGesture() 拖动第二个 CGPoint 时,线条将跟随它(就像它已连接到它一样)。目前这条线不跟随点。 我该怎么做

这是我的代码:

import SwiftUI

struct Point : View {
    var position: CGPoint

    init(_ position: CGPoint) {
        self.position = position
    }
    var body: some View {
        Circle()
            .frame(width: 20)
            .foregroundColor(.white)
            .position(x: position.x, y: position.y)
    }
}

LineWithPoints.swift

struct LineWithPoints : View {
    @State var point1 = Point(.init(x: 0,   y: 0))
    @State var point2 = Point(.init(x: 450, y: 0))
    @State private var offset1 = CGSize.zero
    
    var body: some View {
        let lineBetween = LineBetween(pointPosition: $point2.position)
        
        ZStack {
            lineBetween.stroke(.red, lineWidth: 2)
            point1;               
            point2
                .offset(x: offset1.width, y: offset1.height)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            let x = value.startLocation.x
                            let y = value.startLocation.y
                            let w = value.translation.width
                            let h = value.translation.height
                            offset1 = .init(width: (x + w) - point2.position.x,
                                           height: (y + h) - point2.position.y)
                        }
                )
        }
    }
    struct LineBetween : Shape, @unchecked Sendable {
        @Binding var pointPosition: CGPoint

        func path(in rect: CGRect) -> Path {
            var path = Path()
            path.move(to: CGPoint.zero)
            path.addLine(to: pointPosition)
            path.closeSubpath()
            return path
        }
    }
}

ContentView.swift

struct ContentView : View {
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            LineWithPoints()
        }
    }
}
swiftui uigesturerecognizer cgpoint cgpath
2个回答
0
投票

在您的 DragGesture 中,您没有更改传递给 LineBetweenpointPosition ,您只更改第二个圆的偏移量。您可以为第二个圆的偏移量和形状端点创建相同的变量


0
投票

以下是一些需要纠正的事情:

  • 你的结构
    LineBetween
    只接受一个点作为参数,它假设另一点位于(0,0)。
  • 不需要
    Binding
    ,因为该点是只读的。
  • 与其在
    ZStack
    外部创建形状,然后在堆栈内描画它,不如在一次操作中创建它并在
    ZStack
    内部描画它会更好。
  • 线总是被绘制到point2的位置,但这没有考虑拖动偏移。这就是线路不改变的主要原因。
  • 拖动结束时,您可能想要重置偏移量并更新点 2 的位置,为另一个拖动手势做好准备。

这是解决上述问题的修订版本。它将线绘制到目标点。这是一个单独的状态变量,反映点 2 的最新位置。目标点在拖动过程中更新。

struct LineWithPoints : View {
    @State private var point1: Point
    @State private var point2: Point
    @State private var offset = CGSize()
    @State var targetPoint: CGPoint

    init(
        point1: CGPoint = CGPoint(x: 50, y: 200),
        point2: CGPoint = CGPoint(x: 325, y: 200)
    ) {
        self._point1 = State(initialValue: Point(point1))
        self._point2 = State(initialValue: Point(point2))
        self._targetPoint = State(initialValue: point2)
    }

    struct LineBetween : Shape {
        let point1: CGPoint
        let point2: CGPoint

        func path(in rect: CGRect) -> Path {
            var path = Path()
            path.move(to: point1)
            path.addLine(to: point2)
            path.closeSubpath()
            return path
        }
    }

    var body: some View {
        ZStack {
            LineBetween(
                point1: point1.position,
                point2: targetPoint
            )
            .stroke(.red, lineWidth: 2)
            point1
            point2
                .offset(x: offset.width, y: offset.height)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            offset = value.translation
                            targetPoint = CGPoint(
                                x: point2.position.x + offset.width,
                                y: point2.position.y + offset.height
                            )
                        }
                        .onEnded { value in
                            point2 = Point(targetPoint)
                            offset = CGSize()
                        }
                )
        }
    }
}

LineBetween

© www.soinside.com 2019 - 2024. All rights reserved.