iosswiftswiftui

How to make this type of card component


I am just wondering what are a component to make a Ui design card.cause I saw a lot of these cool card design on pinterest and I was wondering how to make it. Like what are the component to make such a design with SwiftUI

card UI

i have tried it ! the further i have extended the image is this

my image


import SwiftUI
struct RoundedCorners: Shape {
    var radius: CGFloat = 25.0
    var corners: UIRectCorner = .allCorners
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(
            roundedRect: rect,
            byRoundingCorners: corners,
            cornerRadii: CGSize(width: radius, height: radius)
        )
        return Path(path.cgPath)
    }
}
struct ContentView: View {
    var body: some View {
        Image("images")
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: 200, height: 200) // Set your desired image size
            .clipShape(RoundedCorners(radius: 50, corners: [.topLeft, .bottomRight]))
            .shadow(radius: 5)
            .padding()
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

i have tried this but can't .If anyone knows how to make this with a standard.


Solution

  • The basic shape can be built by creating a path and adding arcs to it.

    For the round button bottom-right, it is not possible to attach a tap gesture to a symbol that is passed to the Canvas. Here is what the documentation says on this point:

    The symbol inputs, like all other elements that you draw to the canvas, lack individual accessibility and interactivity, even if the original SwiftUI view has these attributes.

    However, the size of this button is probably fixed, so the path can just be built using this fixed size (instead of passing the button as a symbol). Then the button itself can be shown as an overlay over the canvas, using alignment .bottomTrailing.

    Here is an example to show it working this way:

    struct CardWithInsetCorners: View {
        let label: String
        let image: Image
        let roundButtonDiameter: CGFloat = 44
        let roundedCornerRadius: CGFloat = 10
        let gapToCornerItems: CGFloat = 4
    
        var body: some View {
            Canvas { ctx, size in
                if let label = ctx.resolveSymbol(id: "label") {
    
                    // Draw the label in the top-left corner
                    ctx.draw(label, in: CGRect(origin: .zero, size: label.size))
    
                    // Build a path with rounded corners
                    let path = pathWithRoundedCorners(canvasSize: size, labelSize: label.size)
    
                    // Use the path as clip shape for subsequent drawing operations
                    ctx.clip(to: path)
                }
                // Determine the rectangle for the image when scaled to fill
                let resolvedImage = ctx.resolve(image)
                let rect = rectForImage(canvasSize: size, imageSize: resolvedImage.size)
    
                // Show the image
                ctx.draw(resolvedImage, in: rect)
    
            } symbols: {
                labelInCorner.tag("label")
            }
            .overlay(alignment: .bottomTrailing) {
                roundButton
            }
        }
    
        private func pathWithRoundedCorners(canvasSize: CGSize, labelSize: CGSize) -> Path {
            let wLabel = labelSize.width + gapToCornerItems
            let hLabel = labelSize.height + gapToCornerItems
            let wButton = roundButtonDiameter + gapToCornerItems
            let hButton = roundButtonDiameter + gapToCornerItems
            return Path { path in
    
                // Begin half-way down the left side
                path.move(to: CGPoint(x: 0, y: canvasSize.height / 2))
    
                // Rounded-corner bottom-left of label
                path.addArc(
                    tangent1End: CGPoint(x: 0, y: hLabel),
                    tangent2End: CGPoint(x: wLabel, y: hLabel),
                    radius: roundedCornerRadius
                )
                // Rounded-corner bottom-right of label
                path.addArc(
                    tangent1End: CGPoint(x: wLabel, y: hLabel),
                    tangent2End: CGPoint(x: wLabel, y: 0),
                    radius: (hLabel + gapToCornerItems) / 2
                )
                // Rounded-corner top-right of label
                path.addArc(
                    tangent1End: CGPoint(x: wLabel, y: 0),
                    tangent2End: CGPoint(x: canvasSize.width, y: 0),
                    radius: roundedCornerRadius
                )
                // Rounded-corner top-right
                path.addArc(
                    tangent1End: CGPoint(x: canvasSize.width, y: 0),
                    tangent2End: CGPoint(x: canvasSize.width, y: canvasSize.height - hButton),
                    radius: roundedCornerRadius
                )
                // Rounded-corner top-right of round button
                path.addArc(
                    tangent1End: CGPoint(x: canvasSize.width, y: canvasSize.height - hButton),
                    tangent2End: CGPoint(x: canvasSize.width - wButton, y: canvasSize.height - hButton),
                    radius: roundedCornerRadius
                )
                // Rounded-corner top-left of round button
                path.addArc(
                    tangent1End: CGPoint(x: canvasSize.width - wButton, y: canvasSize.height - hButton),
                    tangent2End: CGPoint(x: canvasSize.width - wButton, y: canvasSize.height),
                    radius: (wButton + gapToCornerItems) / 2
                )
                // Rounded-corner bottom-left of round button
                path.addArc(
                    tangent1End: CGPoint(x: canvasSize.width - wButton, y: canvasSize.height),
                    tangent2End: CGPoint(x: 0, y: canvasSize.height),
                    radius: roundedCornerRadius
                )
                // Rounded-corner bottom-left
                path.addArc(
                    tangent1End: CGPoint(x: 0, y: canvasSize.height),
                    tangent2End: CGPoint(x: 0, y: canvasSize.height / 2),
                    radius: roundedCornerRadius
                )
                path.closeSubpath()
            }
        }
    
        private func rectForImage(canvasSize: CGSize, imageSize: CGSize) -> CGRect {
            let wImage = imageSize.width
            let hImage = imageSize.height
            let scalingFactor = max(canvasSize.width / wImage, canvasSize.height / hImage)
            let w = wImage * scalingFactor
            let h = hImage * scalingFactor
            let xImage = (canvasSize.width - w) / 2
            let yImage = (canvasSize.height - h) / 2
            return CGRect(
                origin: CGPoint(x: xImage, y: yImage),
                size: CGSize(width: w, height: h)
            )
        }
    
        private var labelInCorner: some View {
            Text(label)
                .font(.subheadline)
                .padding(.horizontal, 20)
                .padding(.vertical, 6)
                .background {
                    Capsule()
                        .fill(Color(.systemGray5))
                }
        }
    
        private var roundButton: some View {
            Image(systemName: "heart")
                .resizable()
                .scaledToFit()
                .padding(12)
                .frame(width: roundButtonDiameter, height: roundButtonDiameter)
                .background {
                    Circle()
                        .fill(Color(.systemGray5))
                }
                .onTapGesture {
                    print("+like")
                }
        }
    }
    
    struct ContentView: View {
        var body: some View {
            CardWithInsetCorners(
                label: "Music",
                image: Image(.image3)
            )
            .frame(height: 350)
            .frame(maxHeight: .infinity, alignment: .top)
        }
    }
    

    Screenshot