DEV Community

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

Posted on

Apply ContainerRelativeShape only to specific corners [SwiftUI]

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)
    }
}

Top comments (0)