skip to Main Content

I made a custom shape in SwiftUI with the following code:

struct CustomShape: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
    
        path.move(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
        path.addQuadCurve(to: CGPoint(x: 0, y: rect.minY), control: CGPoint(x: rect.midX, y: rect.minY - 25))
    
        return path
    }
}

The usage of this shape looks like the following:

CustomShape()
    .fill(.ultraThickMaterial)
    .frame(height: 200)

The problem is that if I try to fill it with a color it works perfectly. If I try to fill it with a material only the rectangle seems to get filled, the arc portion remains white:

enter image description here

enter image description here

Do you have an idea how to solve this?

2

Answers


  1. It seems that clipping is being applied when you are using a material, but not when you are using a color. The arc of your path is extending outside the frame of the view.

    You can fix this by making the path fully contained within the rect parameter of the shape:

    func path(in rect: CGRect) -> Path {
        var path = Path()
            
        path.move(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY + 25))
        path.addQuadCurve(to: CGPoint(x: 0, y: rect.minY + 25), control: CGPoint(x: rect.midX, y: rect.minY))
        path.closeSubpath()
        return path
    }
    

    If you really want the material to extend outside the frame then you’ll need to use a container view of some sort.

    Login or Signup to reply.
  2. I’d say that expected effect should be achieved with background and clipShape (assuming that CustomShape is constructed correctly)

    Here is a demo for better visibility (tested with Xcode 13.3 / iOS 15.4)

    Image("background").overlay(
        Rectangle()
             .background(.thinMaterial)   // << here !! (thin for demo)
             .frame(height: 200)
             .clipShape(CustomShape())    // << here !!
        )
    

    demo

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search