Shape
Skip support for SwiftUI.Shape ↗ on Android. Consult the SkipUI module for a complete list of supported SwiftUI.
The following example screens and source code is from SkipUI’s
Showcase sample app
ShapePlayground.swift ↗
import SwiftUI
struct ShapePlayground: View { var body: some View { ScrollView { VStack(spacing: 16.0) { HStack { Text("Capsule") Spacer() ZStack { Capsule() .fill() } .frame(width: 100.0, height: 50.0) .border(.blue) } HStack { Text("Capsule") Spacer() ZStack { Capsule() .fill() } .frame(width: 50.0, height: 100.0) .border(.blue) } HStack { Text("Circle") Spacer() ZStack { Circle() .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("Circle") Spacer() ZStack { Circle() .fill() } .frame(width: 100.0, height: 50.0) .border(.blue) } HStack { Text("Ellipse") Spacer() ZStack { Ellipse() .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("Ellipse") Spacer() ZStack { Ellipse() .fill() } .frame(width: 100.0, height: 50.0) .border(.blue) } HStack { Text("Rectangle") Spacer() ZStack { Rectangle() .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("Rectangle") Spacer() ZStack { Rectangle() .fill() } .frame(width: 100.0, height: 50.0) .border(.blue) } HStack { Text("RoundedRectangle") Spacer() ZStack { RoundedRectangle(cornerRadius: 40.0) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("RoundedRectangle") Spacer() ZStack { RoundedRectangle(cornerSize: CGSize(width: 40.0, height: 20.0)) .fill() } .frame(width: 100.0, height: 50.0) .border(.blue) } HStack { Text("UnevenRoundedRectangle") Spacer() ZStack { UnevenRoundedRectangle(topLeadingRadius: 10.0, bottomLeadingRadius: 20.0, bottomTrailingRadius: 30.0, topTrailingRadius: 40.0) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } Text("Custom").font(.title).bold() HStack { Text("Fill") Spacer() ZStack { CustomShape() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("Stroke") Spacer() ZStack { CustomShape() .stroke(lineWidth: 10.0) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("Rotation") Spacer() ZStack { customPath(in: CGSize(width: 100.0, height: 100.0), transform: CGAffineTransform(rotationAngle: Angle(degrees: 30.0).radians)) } .frame(width: 100.0, height: 100.0) .border(.blue) } Text("Fill & Stroke").font(.title).bold() HStack { Text("fill(.red)") Spacer() ZStack { Circle() .fill(.red) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("fill(.red.gradient)") Spacer() ZStack { Circle() .fill(.red.gradient) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("stroke()") Spacer() ZStack { Circle() .stroke() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("stroke(.red, lineWidth: 10)") Spacer() ZStack { Circle() .stroke(.red, lineWidth: 10.0) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("stroke(.red.gradient, lineWidth: 10)") Spacer() ZStack { Circle() .stroke(.red.gradient, style: StrokeStyle(lineWidth: 10.0)) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("stroke(.red,\n style: StrokeStyle(\n lineWidth: 10.0,\n dash: [10]))") Spacer() ZStack { Circle() .stroke(.red, style: StrokeStyle(lineWidth: 10.0, dash: [10.0])) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("strokeBorder(.red, lineWidth: 10)") Spacer() ZStack { Circle() .strokeBorder(.red, lineWidth: 10.0) } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("fill(.red)\n .stroke(.green, lineWidth: 10)") Spacer() ZStack { if #available(iOS 17, macOS 14, *) { Circle() .fill(.red) .stroke(.green, lineWidth: 10.0) } } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("stroke x2") Spacer() ZStack { if #available(iOS 17, macOS 14, *) { Circle() .stroke(.red, lineWidth: 10.0) .stroke(.green, lineWidth: 5.0) } } .frame(width: 100.0, height: 100.0) .border(.blue) } Text("Transforms").font(.title).bold() HStack { Text("inset(by: 10)") Spacer() ZStack { Rectangle() .inset(by: 10.0) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("offset(x: 30, y: 10)") Spacer() ZStack { Rectangle() .offset(x: 30.0, y: 10.0) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("rotation(Angle(degrees: 45))") Spacer() ZStack { Rectangle() .rotation(Angle(degrees: -30.0)) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("scale(x: 0.5, y: 1.2)") Spacer() ZStack { Rectangle() .scale(x: 0.5, y: 1.2) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("scale(x: 1.0, y: -1.0)") Spacer() ZStack { UnevenRoundedRectangle(topLeadingRadius: 10.0, bottomLeadingRadius: 20.0, bottomTrailingRadius: 30.0, topTrailingRadius: 40.0) .scale(x: 1.0, y: -1.0) .fill() } .frame(width: 100.0, height: 100.0) .border(.blue) } HStack { Text("scale, rotate, offset, stroke") Spacer() ZStack { Rectangle() .scale(x: 0.5, y: 1.2) .rotation(Angle(degrees: -30.0)) .offset(x: 30.0, y: 10.0) .stroke(.red, lineWidth: 10.0) } .frame(width: 100.0, height: 100.0) .border(.blue) } }.padding() } .toolbar { PlaygroundSourceLink(file: "ShapePlayground.swift") } }}
struct CustomShape: Shape { let arcSize = 20.0
func path(in rect: CGRect) -> Path { var path = Path() path.move(to: CGPoint(x: rect.minX, y: rect.minY + arcSize)) path.addLine(to: CGPoint(x: rect.maxX - arcSize - arcSize * 2, y: rect.minY + arcSize)) path.addRelativeArc(center: CGPoint(x: rect.maxX - arcSize - arcSize, y: rect.minY + arcSize), radius: arcSize, startAngle: Angle(degrees: -180.0), delta: Angle(degrees: 180.0)) path.addArc(center: CGPoint(x: rect.maxX - arcSize, y: rect.minY + arcSize + arcSize), radius: arcSize, startAngle: Angle(degrees: -90.0), endAngle: Angle(degrees: 90.0), clockwise: false) path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) return path }}
func customPath(in size: CGSize, transform: CGAffineTransform) -> Path { var path = Path() let rect = CGRect(origin: .zero, size: size).insetBy(dx: 20.0, dy: 0.0) path.addRect(rect, transform: transform) return path}