12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

特定の角のみ ContainerRelativeShape を適用したい [SwiftUI]

Posted at

iOS 14 から登場した自動角丸 ContainerRelativeShape を、特定の角にだけ利用したいという記事です。

ContainerRelativeShape とは

iPhone 11 の端末自体や、 iOS14 から登場した Widget など、各箇所固有の角丸UIが増えてきています。
それぞれの箇所で適切な角丸半径で表示してくれるのが、ContainerRelativeShape です。

目的

左上に配置して ContainerRelativeShape 適用 拡張して左上だけ角丸にする!
  • 特定の角だけ角丸にしたい
  • なおかつただの角丸ではなく自動計算の ContainerRelativeShape を使いたい

これを実現した、一番右の画像の実装を解説します。

コード

カスタム Shape

Shape Protocol を用い、
角の情報を扱うちょうどよい UIRectCorner OptionSet があるので利用して、
独自の ContainerRelativeShapeSpecificCorner Struct を定義します。

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

利用例

// 本来
Image("camera")
    .clipShape(ContainerRelativeShape())

// 今回のやつ (特定の角だけ角丸)
Image("camera")
    .clipShape(ContainerRelativeShapeSpecificCorner(corner: .topLeft, .topRight))

// 全コードサンプル
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)
    }
}
12
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?