Define which corner receives a given cornerRadius in SwiftUI

iOS 17+

In the latest iOS update (iOS 17), a new feature called UnevenRoundedRectangle has been introduced. UnevenRoundedRectangle enables views to specify individual corner radii, allowing for customized corner shapes on a view. With UnevenRoundedRectangle, developers now have the ability to define corner radii independently for each corner of a View, offering greater flexibility and customization in the design of user interfaces.

Usage

import SwiftUI

struct SwiftUIContentView: View {
    var body: some View {
        Rectangle()
            .frame(width: 300, height: 200)
            .foregroundColor(.red)
            .clipShape(
                .rect(
                    topLeadingRadius: 24,
                    bottomTrailingRadius: 60
                )
            )
    }
}

What if you’re supporting an earlier version on iOS?

In the case where you’re using an earlier version of iOS, such as iOS 15 what can you do when you encounter the following error message if attempting to use UnevenRoundedRectangle ?

'rect(topLeadingRadius:bottomLeadingRadius:bottomTrailingRadius:topTrailingRadius:style:)' is only available in iOS 16.0 or newer

Below we create a View that conforms to the Shape protocol to achieve this.

struct RoundedShape: Shape {
    var radius: CGFloat = .zero
    var corners: UIRectCorner = .allCorners

    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(
            roundedRect: rect,
            byRoundingCorners: corners,
            cornerRadii: CGSize(
                width: radius,
                height: radius
            )
        )
        return Path(path.cgPath)
    }
}

Then, we create an extension on View to access a modifier similar to .cornerRadius

extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        RoundedShape(radius: radius, corners: corners)
    }
}

Now similar, to using .clipShape in our example above we can use our custom modifier as follows:

struct SwiftUIContentView: View {
    var body: some View {
        Rectangle()
            .frame(width: 300, height: 200)
            .foregroundColor(.red)
            .clipShape(
                RoundedShape(
                    radius: 24,
                    corners: [
                        .topLeft,
                        .bottomRight
                    ]
                )
            )
    }
}

Resources

Leave a comment