boundingRect in Path doesn't output anything in SwiftUI

143 Views Asked by At

I was trying to create a function for Path that divides the frame in half.

extension Path {
    mutating func divideInHalf() {
        move(to: CGPoint(x: 0, y: boundingRect.midY))
        addLine(to: CGPoint(x: boundingRect.maxX, y: boundingRect.midY))
    }
}

However, this seemed to do nothing. In fact, I tried experimenting with boundingRect but it refused to output anything at all.

struct ContentView: View {
    @State private var text = "waiting for value..."
    
    var body: some View {
        VStack {
            Text(text)  // This stays as "waiting for value..."
            Path { path in
                path.divideInHalf()
                text = "\(path.boundingRect.height)"  // This does nothing
            }
            .stroke()
        }
    }
}

I thought maybe it had something to do with using the inout variable so I tried doing this as well:

struct ContentView: View {
    @State private var text = "waiting for value..."
    
    var body: some View {
        VStack {
            Text(text)  // This stays as "waiting for value..."
            Path { path in
                path.divideInHalf()
                let rect = Path { path in 
                    path.move(to: .zero)
                    path.addLine(to: CGPoint(x: 100, y: 100))
                }.boundingRect  // Getting the value from the instance directly

                text = "\(rect.height)"  // This still does nothing
            }
            .stroke()
        }
    }
}

I tried adding more lines to the path but that still did nothing. Does anyone know how boundingRect works? Why is it not outputting anything, what am I missing?

1

There are 1 best solutions below

2
rob mayoff On

What is the boundingRect of an empty Path?

print(Path { _ in }.boundingRect)
/// (inf, inf, 0.0, 0.0)

In divideInHalf, your calls to move and addLine are passing midY and maxX, which are both CGFloat.inf (infinity). Path appears to ignore such calls.

If you put some content in your Path, divideInHalf will add a subpath. For example:

struct ContentView: View {
    var body: some View {
        VStack {
            Path { path in
                path.addEllipse(in: .init(x: 10, y: 10, width: 100, height: 100))
                path.divideInHalf()
            }
            .stroke()
            .frame(width: 200, height: 200)
            .border(.red)
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())

The horizontal line through the circle is the result of divideInHalf:

circle with a horizontal line through it

Note that you might like the result better if you change the move call in divideInHalf to use boundingRect.minX instead of 0.