DEV Community

loading...
Cover image for Apply ContainerRelativeShape only to specific corners [SwiftUI]

Apply ContainerRelativeShape only to specific corners [SwiftUI]

yuki0n0
Software Engineer, iOS Engineer
・2 min read

This is an article how to round only specific corners using ContainerRelativeShape which have been appeared from iOS 14.

What is ContainerRelativeShape ?

It will round corners of SwiftUI's view with suitable radius.
Corner rounded devices and UIs are increasing such as iPhone 11 and WidgetKit and more.

Purpose

1. Place it in the upper left 2. Apply ContainerRelativeShape 3. Make only upper left corner !

This article describes the implementation of 3.

  • want to round corner to specific corners.
  • want to use CornerRelativeShape of auto calculates not just rounded corner.

Code

Custom Shape

You create ContainerRelativeShapeSpecificCorner struct using Shape protocol and UIRectCorner optionset.

struct ContainerRelativeShapeSpecificCorner: Shape {

    private let corners: [UIRectCorner]

    init(corner: UIRectCorner...) {
        self.corners = corner
    }

    func path(in rect: CGRect) -> Path {
        var p = ContainerRelativeShape().path(in: rect)

        if corners.contains(.allCorners) {
            return p
        }

        if !corners.contains(.topLeft) {
            p.addPath(Rectangle().path(in: CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.width / 2, height: rect.height / 2)))
        }
        if !corners.contains(.topRight) {
            p.addPath(Rectangle().path(in: CGRect(x: rect.origin.x + rect.width / 2, y: rect.origin.y, width: rect.width / 2, height: rect.height / 2)))
        }
        if !corners.contains(.bottomLeft) {
            p.addPath(Rectangle().path(in: CGRect(x: rect.origin.x, y: rect.origin.y + rect.height / 2, width: rect.width / 2, height: rect.height / 2)))
        }
        if !corners.contains(.bottomRight) {
            p.addPath(Rectangle().path(in: CGRect(x: rect.origin.x + rect.width / 2, y: rect.origin.y + rect.height / 2, width: rect.width / 2, height: rect.height / 2)))
        }
        return p
    }
}

Usage examples

// Originally
Image("camera")
    .clipShape(ContainerRelativeShape())

// This article's
Image("camera")
    .clipShape(ContainerRelativeShapeSpecificCorner(corner: .topLeft, .topRight))

// Complete code sample
struct SampleView: View {
    var body: some View {
        Group {
            Image("camera")
                .resizable()
                .scaledToFill()
                .frame(width: 80, height: 80)
                .clipShape(ContainerRelativeShapeSpecificCorner(corner: .topLeft))
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
        .padding(8)
    }
}

Discussion (0)