Search code examples
iosswiftswiftui

Design an Apple Wallet pass style card in SwiftUi


I'm struggling to achieve the design of an Apple Wallet pass card in my SwiftUI app. My goal is to have have a card with a little cutout at the top juste like on this screenshot. Thanks in advance for the help apple wallet pass 🙏

Here is what I've tried so far:

GeometryReader { geometry in
            ZStack() {
                HStack {
                    Spacer()
                    Ellipse()
                        .frame(width: geometry.size.width * 0.2, height: 50) // adjust width and height as needed
                        .foregroundColor(.white) // assuming a white ellipse
                        .offset(y: -120) // move the ellipse up by half its height
                    Spacer()
                }
                VStack(alignment: .leading, spacing: 8) {
                    HStack {
                        Spacer()
                        Text("Card")
                        Spacer()
                    }
                    .frame(height: 200)
                    // Rest of your VStack content
                }
            }
            .padding()
            .background(Color("BuoyPurple")) // Replace with your color
            .cornerRadius(8)
            .frame(width: geometry.size.width, height: 300) // adjust height as needed
        }
        .padding()

enter image description here

Problem is that I can't do the shadow effect that way


Solution

  • Since you want to add a shadow to the background, I would suggest using a custom Shape for this.

    • The shape can be formed quite easily as a rounded rectangle with an inset subtracted from the top.
    • One way to create the path of the inset is to use .addQuadCurve.
    struct ContentView: View {
    
        struct CardShape: Shape {
            func path(in rect: CGRect) -> Path {
                let insetWidth = 50.0
                let insetHeight = 20.0
                var insetPath = Path()
                insetPath.move(to: CGPoint(x: rect.midX - (insetWidth / 2), y: rect.minY))
                insetPath.addQuadCurve(
                    to: CGPoint(x: rect.midX + (insetWidth / 2), y: rect.minY),
                    control: CGPoint(x: rect.midX, y: rect.minY + insetHeight)
                )
                insetPath.closeSubpath()
                return Path(roundedRect: rect, cornerRadius: 8)
                    .subtracting(insetPath)
            }
        }
    
        var body: some View {
            VStack(alignment: .leading, spacing: 8) {
                HStack {
                    Spacer()
                    Text("Card")
                    Spacer()
                }
                .frame(height: 200)
                // Rest of your VStack content
            }
            .padding()
            .background(
                CardShape()
                    .fill(.indigo) // Color("BuoyPurple"))
                    .shadow(color: Color(white: 0.3), radius: 8)
            )
            .padding()
        }
    }
    

    Screenshot