Home > Blockchain >  SwiftUI: Custom shape material fill does not work
SwiftUI: Custom shape material fill does not work

Time:04-29

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?

CodePudding user response:

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.

CodePudding user response:

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

  • Related