SwiftUI using the width of a view in its modifiers

I'm trying to create a rounded button with dynamic height/width. To be perfectly rounded, the corner radius must be equal to half of the button's height. Is there a way to dynamically update the corner radius used by the modifier as the view's bound's are changed?

This is what I have so far for the button's label:
Code Block
HStack {
Image(systemName: "plus")
Text("Add")
}
.padding(.vertical, 5)
.padding(.horizontal)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(lineWidth: 1))

Answered by OOPer in 616280022
You can define your own shape, and use CGRect in its implementation of path(in:).
Code Block
struct CircularEndBox: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let cornerSize: CGSize
        if rect.width > rect.height {
            cornerSize = CGSize(width: rect.height/2, height: rect.height/2)
        } else {
            cornerSize = CGSize(width: rect.width/2, height: rect.width/2)
        }
        path.addRoundedRect(in: rect, cornerSize: cornerSize)
        return path
    }
}


You can use it the same way as other Shapes.
Code Block
            HStack {
                    Image(systemName: "plus")
                    Text("Add")
            }
            .padding(.vertical, 5)
            .padding(.horizontal)
            .overlay(CircularEndBox().stroke(lineWidth: 1))



This is actually a little complex to do. You should definitely watch the great talk "SwiftUI under the hood" given by Chris Eidhof in BA: Swiftable conferece. He goes through the entire process of creating a dynamic circular button while explaining some interesting details of the framework. The video is available on Youtube.
Thanks for your reply, I'll definitely give it a watch, cheers 🙂
Accepted Answer
You can define your own shape, and use CGRect in its implementation of path(in:).
Code Block
struct CircularEndBox: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let cornerSize: CGSize
        if rect.width > rect.height {
            cornerSize = CGSize(width: rect.height/2, height: rect.height/2)
        } else {
            cornerSize = CGSize(width: rect.width/2, height: rect.width/2)
        }
        path.addRoundedRect(in: rect, cornerSize: cornerSize)
        return path
    }
}


You can use it the same way as other Shapes.
Code Block
            HStack {
                    Image(systemName: "plus")
                    Text("Add")
            }
            .padding(.vertical, 5)
            .padding(.horizontal)
            .overlay(CircularEndBox().stroke(lineWidth: 1))



That's perfect, really elegant, thanks a lot :)
SwiftUI using the width of a view in its modifiers
 
 
Q