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
i have tried it ! the further i have extended the image is this
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.
The basic shape can be built by creating a path and adding arcs to it.
One approach is to create a custom Shape
, as you were doing originally. However, doing it this way, it will be difficult to reserve the correct amount of space for showing the label in the top-left corner, unless the size of the label is fixed of course.
If you want to show a label that can contain text of varying size and also adapt to dynamic font sizes, then an alternative approach is to use a Canvas
. You can then pass in the label as a "symbol" for the canvas to use.
A Canvas
receives a GraphicsContext
as parameter and this lets you measure the size of images and other symbols. So this makes it possible to build a path that fits exactly to the size of the label.
An easy way to draw the curves is to use addArc(tangent1End:tangent2End:radius:transform:). Here you just pass in the points that you would use if you were drawing the shape with square corners, instead of rounded corners.
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)
}
}