
It took me a little time to figure ot how to draw a simple diamond using Xcode 16.0 and Swift 5. The trouble I ran into was the lines connecting the start and end point were not closing. I could fudge it a little by increasing the length of the start and end lines – BUT that wouldn’t really work because with width of the stroke changes the required fudge-factor.
The solution to the problem is calling closeSubpath() on your path variable to format the start/end match points properly.
Now, you wouldn’t see this problem if you were coding with fill or stroking in a different fashion than using .stroke or .strokeBorder as I did. If you were just filling then you don’t see the stroke lines. Also stroke works perfect with a 1 pixel line without calling closeSubpath(). It’s when the. line gets to be about 4 pixels wide that it becomes visible. To use those two methods, Diamond needed to conform to InsettableShape, and thus implement:
inset(by amount: CGFloat) -> some InsettableShape

You control the shape of the rendered diamond by placing it into a container and it will fit the size.
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Diamond()
.inset(by: 5)
.fill(.red)
.strokeBorder(.blue, lineWidth: 10)
.frame(width:200, height:300)
.background(.green)
Diamond()
.inset(by: 15)
.fill(.orange)
.strokeBorder(.black, lineWidth: 16)
.frame(width:150, height:250)
.background(.green)
}
.padding()
.background(.yellow)
}
}
#Preview {
ContentView()
}
//
//
// Diamond.swift
//
import SwiftUI
import CoreGraphics
// -------------------------------------------------------------------------
// We make diamond InsetableShape and add func required by protocol: inset()
// then we can use stroke on shape and get an outline
// -------------------------------------------------------------------------
struct Diamond: InsettableShape {
var insetAmount = 0.0
func inset(by amount: CGFloat) -> some InsettableShape {
var diamond = self
diamond.insetAmount += amount
return diamond
}
func path(in rect: CGRect) -> Path {
// draws counter clockwise from 3 o'clock
let start0 = CGPoint(x: rect.maxX - insetAmount, y: rect.midY)
// 3 o'clock to 12 o'clock
let end0 = CGPoint(x: rect.midX, y: rect.maxY - insetAmount)
// 12 o'clock to 9 o'clock
let end1 = CGPoint(x: rect.minX + insetAmount, y: rect.midY)
// 9 o'clock to 6 o'clock
let end2 = CGPoint(x: rect.midX, y: rect.minY + insetAmount)
// 6 o'clock to 3 o'clock
let end3 = CGPoint(x: rect.maxX - insetAmount, y: rect.midY)
var p = Path()
p.move(to: start0)
p.addLines([start0, end0, end1, end2, end3])
// complete drawing the diamond by applying
// closeSubpath - otherwise joints won't fill
// in between start point and end point
p.closeSubpath()
return p
}
}





















