【SwiftUI】Viewの一角だけ角丸にする方法

この記事では、Viewの一角だけ角丸にする方法紹介します。

やりたいこと

こんな感じです。

現時点のSwiftUIでは、一角だけ角丸にするというのは簡単にはできません。。

探してみたら一応角丸にする方法がありましたので、この記事で共有していきたいと思います。

Qiitaの記事から2つの方法が見つかりました。

  1. 【SwiftUI】 CornerRadiusを一部にのみ適用する
  2. 「一部だけ角丸にする」をSwiftUIで実現する

実装方法

1つ目の記事の方法

参考 【SwiftUI】 CornerRadiusを一部にのみ適用するQiita

シンプルに書けます。

以下のStructをどこかに貼り付けてください。

struct RoundedCorners: View {
    var color: Color = .clear
    var tl: CGFloat = 0.0
    var tr: CGFloat = 0.0
    var bl: CGFloat = 0.0
    var br: CGFloat = 0.0
    
    var body: some View {
        GeometryReader { geometry in
            Path { path in
                let w = geometry.size.width
                let h = geometry.size.height
                
                let tr = min(min(tr, h/2), w/2)
                let tl = min(min(tl, h/2), w/2)
                let bl = min(min(bl, h/2), w/2)
                let br = min(min(br, h/2), w/2)
                
                path.move(to: CGPoint(x: w/2.0, y: 0))
                path.addLine(to: CGPoint(x: w-tr, y: 0))
                path.addArc(center: CGPoint(x: w-tr, y: tr), radius: tr, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
                path.addLine(to: CGPoint(x: w, y: h-br))
                path.addArc(center: CGPoint(x: w-br, y: h-br), radius: br, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)
                path.addLine(to: CGPoint(x: bl, y: h))
                path.addArc(center: CGPoint(x: bl, y: h-bl), radius: bl, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)
                path.addLine(to: CGPoint(x: 0, y: tl))
                path.addArc(center: CGPoint(x: tl, y: tl), radius: tl, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false)
            }
            .fill(color)
        }
    }
}

その後に、以下のように書くと一部の角を丸くできます。

VStack {
    Text("Hello, world!")
        .padding()
    Text("Hello, world!")
        .padding()
    Text("Hello, world!")
        .padding()
}
.background(RoundedCorners(color: .green, tl: 30, tr: 0, bl: 0, br: 30))

colorは背景色、tl(top leftの略)は左上、tr(top right)は右上、bl(bottom leftの略)は左下、br(bottom right)は右下です。

2つ目の記事の方法

参考 「一部だけ角丸にする」をSwiftUIで実現するQiita

以下のコードをどこかに貼り付けてください。

struct PartlyRoundedCornerView: UIViewRepresentable {
    let cornerRadius: CGFloat
    let maskedCorners: CACornerMask
    
    func makeUIView(context: UIViewRepresentableContext<PartlyRoundedCornerView>) -> UIView {
        let uiView = UIView()
        uiView.layer.cornerRadius = cornerRadius
        uiView.layer.maskedCorners = maskedCorners
        uiView.backgroundColor = .white
        return uiView
    }
    
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PartlyRoundedCornerView>) {
    }
}


struct PartlyRoundedCornerModifier: ViewModifier {
    let cornerRadius: CGFloat
    let maskedCorners: CACornerMask
    
    func body(content: Content) -> some View {
        content.mask(PartlyRoundedCornerView(cornerRadius: self.cornerRadius, maskedCorners: self.maskedCorners))
    }
}

extension View {
    func cornerRadius(_ radius: CGFloat, maskedCorners: CACornerMask) -> some View {
        self.modifier(PartlyRoundedCornerModifier(cornerRadius: radius, maskedCorners: maskedCorners))
    }
}

その後で、以下のように書くと一部の角を丸くすることができます。

VStack {
    Text("Hello, world!")
        .padding()
    Text("Hello, world!")
        .padding()
    Text("Hello, world!")
        .padding()
}
.background(.green)
.cornerRadius(30, maskedCorners: [.layerMinXMinYCorner, .layerMaxXMaxYCorner])

丸みの大きさを決めて、maskedCorners:の中で丸くする場所を決めます。

  • .layerMinXMinYCornerが左上
  • .layerMaxXMinYCornerが右上
  • .layerMinXMaxYCornerが左下
  • .layerMaxXMaxYCornerが右下

です。

まとめ

二つ目の方法はスマートですが、角の大きさを個別に変えることができません。ですので、角の大きさを個別に変えたいとなると、1つ目の方法がおすすめです。