TruMan1
TruMan1

Reputation: 36098

Clip image with semi-circle mask?

I'm trying to add a circle background for an image, then clip the image using a semi-circle of the background. This is what I'm trying to end up with:

enter image description here

In SwiftUI, I put together something but stuck on what clipShape should I use:

Circle()
    .fill(Color.blue)
    .aspectRatio(contentMode: .fit)
    .frame(width: 48)
    .padding(.top, 8)
    .overlay(
        Image("product-sample1")
            .resizable()
            .scaledToFit()
            //.clipShape(???)
    )

This is what it looks like:

enter image description here

I'm not sure how to achieve this but was given a clue to use this approach:

enter image description here

How can this be achieved in SwiftUI, or is there a better approach to doing this?

Upvotes: 3

Views: 758

Answers (1)

Asperi
Asperi

Reputation: 257729

You can create own shape. Below is a simple demo variant (for square content).

private struct DemoClipShape: Shape {
    func path(in rect: CGRect) -> Path {
        Path {
            $0.move(to: CGPoint.zero)
            $0.addLine(to: CGPoint(x: rect.maxX, y: 0))
            $0.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
            $0.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.midY, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)
            $0.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.midY, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)
            $0.addLine(to: CGPoint.zero)
        }
    }
}

demo

And here is a sample of how it could be applied - due to padding we need to offset clipping (mask) to compensate locations (also it can be passed as constant into shape constructor, which will be more correct and accurate, but I leave it for you):

// used larger values for better visibility
Circle()
    .fill(Color.blue)
    .frame(width: 148, height: 148)
    .padding(.top, 18)
    .padding(.bottom, 10)
    .overlay(
        Image("product-sample1")
            .resizable()
            .scaledToFit()
    )
    .mask(DemoClipShape().offset(x: 0, y: -11))    // << here !!

gives

enter image description here

Upvotes: 2

Related Questions