SwiftUI How to connect objects with a line?

Viewed 834

I have three circles and would like draw lines connecting 1<->2 and 2<->3. There doesn't seem to be a Line shape, and even if it would how would I specify the connection. Any ideas?

My current code looks like this

struct ConnectedCircles: View {
    var body: some View {
        VStack {
            Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
                .background(Circle().foregroundColor(Color(.systemBackground)))
                .frame(width: 30, height: 30)
                
            Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
                .background(Circle().foregroundColor(Color(.systemBackground)))
                .frame(width: 30, height: 30)
            
            Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
                .background(Circle().foregroundColor(Color(.systemBackground)))
                .frame(width: 30, height: 30)
            
        }
    }
}

And produces three unconnected circles.

enter image description here

While I would like to produce something like this

enter image description here

1 Answers

one of the easiest ways to achieve what you want is to draw a Rectangle below your Circles as the connecting line using a ZStack. like this:

struct ConnectedCircles: View {
    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.blue)
                .frame(width: 2, height: 100)
            VStack {
                Circle()
                .strokeBorder(Color.blue,lineWidth: 4)
                    .background(Circle().foregroundColor(Color(.systemBackground)))
                    .frame(width: 30, height: 30)
                    
                Circle()
                .strokeBorder(Color.blue,lineWidth: 4)
                    .background(Circle().foregroundColor(Color(.systemBackground)))
                    .frame(width: 30, height: 30)
                
                Circle()
                .strokeBorder(Color.blue,lineWidth: 4)
                    .background(Circle().foregroundColor(Color(.systemBackground)))
                    .frame(width: 30, height: 30)
                
            }
        }
    }
}

another solution is creating a custom Shape as our line.:

struct VerticalLine: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
        return path
    }
}

struct ConnectedCircles: View {
    var body: some View {
        ZStack {
            Line()
            VerticalLine()
                .stroke(Color.blue, lineWidth: 4)
                .frame(width: 20, height: 100)
            VStack {
                Circle()
                .strokeBorder(Color.blue,lineWidth: 4)
                    .background(Circle().foregroundColor(Color(.systemBackground)))
                    .frame(width: 30, height: 30)
                    
                Circle()
                .strokeBorder(Color.blue,lineWidth: 4)
                    .background(Circle().foregroundColor(Color(.systemBackground)))
                    .frame(width: 30, height: 30)
                
                Circle()
                .strokeBorder(Color.blue,lineWidth: 4)
                    .background(Circle().foregroundColor(Color(.systemBackground)))
                    .frame(width: 30, height: 30)
                
            }
        }
    }
}

and you can do it even without using a ZStack. You should set your VStack's spacing to 0 and draw lines between Circles.

struct VerticalLine: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
        return path
    }
}

struct ConnectedCircles: View {
    var body: some View {
            
        VStack(spacing: 0) {
            Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
                .frame(width: 30, height: 30)
            Line()
            VerticalLine()
                .stroke(Color.blue, lineWidth: 4)
                .frame(width: 20, height: 10)
            Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
                .frame(width: 30, height: 30)
            Line()
            VerticalLine()
                .stroke(Color.blue, lineWidth: 4)
                .frame(width: 20, height: 10)
            Circle()
            .strokeBorder(Color.blue,lineWidth: 4)
                .frame(width: 30, height: 30)
            
        }
    }
}
Related