user3069232
user3069232

Reputation: 8995

Drawing 2 dots and a line between them in SwiftUI

Swift 5.5 iOS 15

Drawing 2 dots at random places, noting their origins and then trying to use the information to draw a line between them.

Almost there, and yet the result is wrong? What am I doing wrong?

struct ContentView: View {
@State var cords:[CGPoint] = []
@State var showMe = false
var body: some View {
    ZStack {
        ForEach((0..<2), id:\.self) {foo in
            Circle()
                .fill(Color.blue)
                .frame(width: 64, height: 64)
            
                .background(GeometryReader { geo in
                    Circle()
                        .stroke(Color.red, lineWidth: 2)
                        .frame(width: 64, height: 64)
                        .onAppear {
                            cords.append(CGPoint(x: geo.frame(in: .global).origin.x, y: geo.frame(in: .global).origin.y))
                        }
                })
                .position(returnRandom())
                .task {
                    if cords.count > 1 {
                        print("cords \(cords)")
                        showMe = true
                    }
                }
        }
    }
    ZStack {
        if showMe {
            Connected(cords: $cords)
                .stroke(Color.black, lineWidth: 1)
        }
    }
}
func returnRandom() -> CGPoint {
    let x = Double.random(in: 0..<width)
    let y = Double.random(in: 0..<height)
    return CGPoint(x: x, y: y)
}
}

struct Connected: Shape {
@Binding var cords:[CGPoint]
func path(in rect: CGRect) -> Path {
    var path = Path()
    path.move(to: cords[0])
    path.addLine(to: cords[1])
    return path
}
}

Also tried ...

cords.append(CGPoint(x: geo.frame(in: .global).midX, y: geo.frame(in: .global).midY))

Upvotes: 1

Views: 1533

Answers (1)

burnsi
burnsi

Reputation: 7754

The issue is the way you implemented this.

You are modifying your state after Circles have appeared and the coordinates have been calculated.

.task {
    if cords.count > 1 {
        print("cords \(cords)")
        showMe = true
    }
}    

so your view gets reavaluated and your Circles are redrawn at a new position without calling onAppear(). Your line is still drawn with the old set of coordinates.

Set a breakpoint at:

let x = Double.random(in: 0..<width)

and you will see it gets hit 4 times.

Better:

Create an empty array in view for coordinates. Wrap ForEach in condition. Set an onApear modifier on the view containing your circles. Calculate your coordinates and append them. Draw your lines.

Or:

Create an initializer to calculate Points. Or initialize the Array with random Coordinates.

Upvotes: 1

Related Questions