{"id":85,"date":"2022-07-30T11:54:29","date_gmt":"2022-07-30T10:54:29","guid":{"rendered":"https:\/\/techjourney.me\/?p=85"},"modified":"2022-07-30T11:54:29","modified_gmt":"2022-07-30T10:54:29","slug":"swiftui-shapes","status":"publish","type":"post","link":"https:\/\/techjourney.me\/index.php\/2022\/07\/30\/swiftui-shapes\/","title":{"rendered":"SwiftUI Shapes"},"content":{"rendered":"\n
SwiftUI provides the Shape<\/a> protocol which allows developers to create any customs shape they want. It also provides 5 concrete shapes out of the box.<\/p>\n\n\n\n Lets start with the 5 shapes shipped in SwiftUI:<\/p>\n\n\n\n The important thing to note here are the configurable options and the default configurations that these shapes take on:<\/p>\n\n\n\n Shape protocol allows us to create custom shapes that we can use exactly as we used the built-in shapes above. The only thing required to fulfill the Shape protocol is to provide an implementation of Let’s start with a very simple shape i.e. a checkmark as it only consists of 2 lines. Create a new file called We first move to the point where we want to start drawing. The default starting point is (0, 0) i.e. top left. We move to the middle of leading edge above. Then we add 2 lines starting from that point. First one from middle of leading edge to the bottom edge and from there to almost to the top right corner of the rect. Note that we are taking into consideration the passed in rect so the shape will adapt to the frame the user may set on it. We have to set the Checkmark to be stroked explicitly because as we discussed in the last section that all shapes are filled by default.<\/p>\n\n\n\n Let’s try to draw an infinity symbol which is only a tiny bit more complicated than checkmark. Create a new file called We start drawing at the centre of the rect and then add 4 quad curves from centre to middle of trailing edge, back to centre, from centre to middle of leading edge and back to centre again. Quad curves require a control point that dictates the shape of the curve. The curve does not actually touch the control point, it impacts the shape of the curve by pulling the curve towards control point. The control points we use here are in the 4 corners. It is a good exercise to play with these data points to learn the impact of these values on the resulting shape<\/p>\n","protected":false},"excerpt":{"rendered":" SwiftUI provides the Shape protocol which allows developers to create any customs shape they want. It also provides 5 concrete shapes out of the box. Built-in Shapes Lets start with the 5 shapes shipped in SwiftUI: The important thing to note here are the configurable options and the default configurations that these shapes take on: … <\/p>\nBuilt-in Shapes<\/h2>\n\n\n\n
struct ContentView: View {\n var body: some View {\n VStack {\n Rectangle()\n\n RoundedRectangle(cornerRadius: 12, style: .continuous)\n .stroke(lineWidth: 5)\n\n Ellipse()\n .fill(.red)\n\n Capsule()\n .fill(gradient)\n\n Circle()\n .stroke(angularGradient, lineWidth: 5)\n }\n .padding()\n }\n\n\u00a0\u00a0\u00a0\u00a0var gradient: LinearGradient {\n LinearGradient(\n colors: [.blue, .purple],\n startPoint: .leading,\n endPoint: .trailing\n )\n }\n\n var angularGradient: AngularGradient {\n AngularGradient(\n colors: [.blue, .purple],\n center: .center\n )\n }\n}<\/code><\/pre><\/div>\n\n\n\n
Color<\/code> to be used to fill or stroke the shape as in the Ellipse<\/a> example above where we filled it with red colour<\/li>
Color<\/code> but instead we can pass
Gradient<\/code> to it too. In the above example, we use gradients to fill the Capsule<\/a> and stroke the Circle<\/a><\/li><\/ul>\n\n\n
Custom Shape<\/h2>\n\n\n\n
func path(in rect: CGRect) -> Path<\/code> which returns a Path that describes the shape we want to draw inside the passed in rect.<\/p>\n\n\n\n
Checkmark<\/h3>\n\n\n\n
Checkmark.swift<\/code> as below:<\/p>\n\n\n\n
import SwiftUI\n\nstruct Checkmark: Shape {\n let startPoint = CGPoint(x: 0.0, y: 0.5)\n let linePoints: [CGPoint] = [\n .init(x: 0.3, y: 1.0),\n .init(x: 1.0, y: 0.1)\n ]\n\n func path(in rect: CGRect) -> Path {\n let width = rect.size.width\n let height = rect.size.height\n\n var path = Path()\n path.move(\n to: .init(\n x: startPoint.x * width,\n y: startPoint.y * height\n )\n )\n\n for linePoint in linePoints {\n path.addLine(\n to: .init(\n x: linePoint.x * width,\n y: linePoint.y * height\n )\n )\n }\n return path\n }\n}\n\nstruct Checkmark_Previews: PreviewProvider {\n static var previews: some View {\n VStack {\n Checkmark()\n .stroke(lineWidth: 10.0)\n .frame(width: 100, height: 100)\n .padding()\n\n Checkmark()\n .stroke(\n style: .init(\n lineWidth: 10.0,\n lineCap: .round,\n lineJoin: .round\n )\n )\n .frame(width: 100, height: 100)\n .padding()\n }\n }\n}<\/code><\/pre><\/div>\n\n\n
<\/figure><\/div>\n\n\n
Infinity<\/h3>\n\n\n\n
Infinity.swift<\/code> and add the code below:<\/p>\n\n\n\n
struct InfinitySegment {\n var toPoint: CGPoint\n var controlPoint: CGPoint\n}\n\nstruct Infinity: Shape {\n\n var segments: [InfinitySegment] = [\n InfinitySegment(\n toPoint: .init(x: 1.0, y: 0.5),\n controlPoint: .init(x: 1.0, y: 0.0)\n ),\n InfinitySegment(\n toPoint: .init(x: 0.5, y: 0.5),\n controlPoint: .init(x: 1.0, y: 1.0)\n ),\n InfinitySegment(\n toPoint: .init(x: 0.0, y: 0.5),\n controlPoint: .init(x: 0.0, y: 0.0)\n ),\n InfinitySegment(\n toPoint: .init(x: 0.5, y: 0.5),\n controlPoint: .init(x: 0.0, y: 1.0)\n )\n ]\n\n func path(in rect: CGRect) -> Path {\n let width = rect.size.width\n let height = rect.size.height\n let center = CGPoint(x: 0.5 * width, y: 0.5 * height)\n\n var path = Path()\n path.move(to: center)\n\n for segment in segments {\n path.addQuadCurve(\n to: CGPoint(\n x: segment.toPoint.x * width,\n y: segment.toPoint.y * height\n ),\n control: CGPoint(\n x: segment.controlPoint.x * width,\n y: segment.controlPoint.y * height\n )\n )\n }\n\n return path\n }\n}\n\n\nstruct Inifinity_Previews: PreviewProvider {\n static var previews: some View {\n VStack {\n Infinity()\n .stroke(Color.black, lineWidth: 10.0)\n .frame(height: 300)\n .padding()\n\n Infinity()\n .fill(\n LinearGradient(\n colors: [.blue, .purple],\n startPoint: .top,\n endPoint: .bottom\n )\n )\n }\n }\n}<\/code><\/pre><\/div>\n\n\n
<\/figure><\/div>\n\n\n