SwiftUI:如何一个接一个地连接 2 个以上的点

SwiftUI: How to connect more than 2 dots, one by one

我正在制作一个应用程序,我在其中生成具有随机位置的点。我想用线连接第一个点和第二个点,然后用线连接第二个点和第三个点,依此类推。 我的问题是它正在连接第二个与第三个,但同时第一个正在连接第三个。我不想那样。请帮忙。

这是我的代码:

struct Dot: Hashable {
    var x: CGFloat
    var y: CGFloat
}

struct TestShit: View {
    @State var lastx = 0.0
    @State var lasty = 0.0
    @State var dots = [Dot]()
    var body: some View {
        VStack{
            ZStack{
                ForEach(dots, id: \.self){ dot in
                    Circle()
                        .frame(width: 5, height: 5)
                        .position(x: dot.x, y: dot.y)
                    Path { path in
                        path.move(to: CGPoint(x: lastx, y: lasty))
                        path.addLine(to: CGPoint(x: dot.x, y: dot.y))
                    }.stroke(.green, lineWidth: 5)
                }
            }
            Spacer()
            Button {
                let randx = CGFloat.random(in: 100...300)
                let randy = CGFloat.random(in: 100...300)
                dots.append(Dot(x: randx, y: randy))
                lastx = randx
                lasty = randy
            } label: {
                Text("Button")
            }
        }
    }
}

这里我只维护1条路径,每次追加,而不是在ForEach中多于1条路径

import Combine
import SwiftUI

struct Dot: Hashable {
    var x: CGFloat
    var y: CGFloat
}

class Model: ObservableObject {
    @Published
    var dots: [Dot] = []

    @Published
    var path: UIBezierPath?

    func addDot(x: CGFloat, y: CGFloat) {
        dots.append(Dot(x: x, y: y))
        let randomPoint = CGPoint(x: x, y: y)

        guard let path = path else {
            path = UIBezierPath()
            path?.move(to: randomPoint)
            path?.lineWidth = 2
            return
        }

        path.addLine(to: CGPoint(x: x, y: y))
    }
}

struct TestIt: View {
    @ObservedObject
    var model: Model
    
    var body: some View {
        VStack{
            ZStack{
                if let path = model.path {
                    Path(path.cgPath)
                        .stroke(.green, lineWidth: 5)
                }
                ForEach(model.dots, id: \.self){ dot in
                    Circle()
                        .frame(width: 5, height: 5)
                        .position(x: dot.x, y: dot.y)
                }
            }
            Spacer()
            Button {
                let randx = CGFloat.random(in: 100...300)
                let randy = CGFloat.random(in: 100...300)

                model.addDot(x: randx, y: randy)
            } label: {
                Text("Button")
            }
        }
    }
}

您可能想要看起来更好看的东西

Path(path.cgPath.copy(strokingWithWidth: 5, lineCap: .round, lineJoin: .round, miterLimit: 0))
                .stroke(.green, lineWidth: 5)

问题在于这个循环:

Path { path in
    path.move(to: CGPoint(x: lastx, y: lasty))
    path.addLine(to: CGPoint(x: dot.x, y: dot.y))
}.stroke(.green, lineWidth: 5)

您正在创建多条线段,方法是移动到同一点,然后向不同的点添加一条线。

您想做的是:

  • 设置一个“起点”
  • 移动到那个点
  • 对于每个点,在下一个点上加一行

看看这里的区别:

import SwiftUI

struct Dot: Hashable {
    var x: CGFloat
    var y: CGFloat
}

struct DotsView: View {
    // initialize start point
    var startX = CGFloat.random(in: 100...300)
    var startY = CGFloat.random(in: 100...300)
    
    @State var dots = [Dot]()
    var body: some View {
        VStack{
            ZStack{
                Path { path in
                    // move to start point
                    path.move(to: CGPoint(x: startX, y: startY))
                    dots.forEach { dot in
                        // add line to each dot
                        path.addLine(to: CGPoint(x: dot.x, y: dot.y))
                    }
                }.stroke(.green, lineWidth: 5)
                // draw the start point circle in red
                Circle()
                    .fill(Color.red)
                    .frame(width: 5, height: 5)
                    .position(x: startX, y: startY)
                // draw each dot circle in blue
                ForEach(dots, id: \.self){ dot in
                    Circle()
                        .fill(Color.blue)
                        .frame(width: 5, height: 5)
                        .position(x: dot.x, y: dot.y)
                }
            }
            Spacer()
            Button {
                let randx = CGFloat.random(in: 100...300)
                let randy = CGFloat.random(in: 100...300)
                // add a dot point
                dots.append(Dot(x: randx, y: randy))
            } label: {
                Text("Button")
            }
        }
    }
}