I have a Hexagon path with this code and photo:
struct HorizontalHexagon: InsettableShape {
var insetAmount: CGFloat = CGFloat.zero
func path(in rect: CGRect) -> Path {
return Path { path in
path.move(to: CGPoint(x: rect.minX + insetAmount, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX/4.0, y: rect.minY + insetAmount))
path.addLine(to: CGPoint(x: rect.maxX - rect.maxX/4.0, y: rect.minY + insetAmount))
path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX - rect.maxX/4.0, y: rect.maxY - insetAmount))
path.addLine(to: CGPoint(x: rect.maxX/4.0, y: rect.maxY - insetAmount))
path.closeSubpath()
}
}
func inset(by amount: CGFloat) -> some InsettableShape {
var myShape: Self = self
myShape.insetAmount += amount
return myShape
}
}
However, when I use this defined path to build another shape, there is a size and shape deformation. I don't see any mistakes in my code, but for some unknown reason, this issue occurs.
struct FinalShape: InsettableShape {
var insetAmount: CGFloat = CGFloat.zero
let size1: Double = 4.0
func path(in rect: CGRect) -> Path {
return Path { path in
let makeSize1: Double = rect.width/size1
let makeSize2: Double = rect.width - makeSize1
let horizontalHexagon = HorizontalHexagon(insetAmount: insetAmount)
path.addPath(horizontalHexagon.path(in: CGRect(origin: CGPoint(x: rect.minX + makeSize1/2, y: rect.minY), size: CGSize(width: makeSize2, height: makeSize1))))
path.addPath(horizontalHexagon.path(in: CGRect(origin: CGPoint(x: rect.minX + makeSize1/2, y: rect.midY - makeSize1/2), size: CGSize(width: makeSize2, height: makeSize1))))
path.addPath(horizontalHexagon.path(in: CGRect(origin: CGPoint(x: rect.minX + makeSize1/2, y: rect.maxY - makeSize1), size: CGSize(width: makeSize2, height: makeSize1))))
}
}
func inset(by amount: CGFloat) -> some InsettableShape {
var myShape: Self = self
myShape.insetAmount += amount
return myShape
}
}
My code for ContentView:
struct ContentView: View {
var body: some View {
FinalShape()
.strokeBorder(style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
.background(Color.purple)
.cornerRadius(5.0)
.padding()
}
}
UPDATED:
struct HorizontalHexagon: InsettableShape {
var insetAmount: CGFloat = CGFloat.zero
func path(in rect: CGRect) -> Path {
return Path { path in
path.move(to: CGPoint(x: rect.minX + insetAmount, y: rect.midY))
path.addLine(to: CGPoint(x: rect.width/4, y: rect.minY + insetAmount))
path.addLine(to: CGPoint(x: rect.maxX - rect.width/4, y: rect.minY + insetAmount))
path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX - rect.width/4, y: rect.maxY - insetAmount))
path.addLine(to: CGPoint(x: rect.width/4, y: rect.maxY - insetAmount))
path.closeSubpath()
}
}
func inset(by amount: CGFloat) -> some InsettableShape {
var myShape: Self = self
myShape.insetAmount += amount
return myShape
}
}
When implementing a Shape
, do not assume rect.origin == .zero
.
SwiftUI calls rect(in:)
with a zero-origin rectangle almost all the time, but in this case you are calling rect(in:)
yourself, with rectangles that have a non-zero origin.
So
rect.maxX / 4
should be rect.minX + rect.width / 4
rect.maxX - rect.maxX / 4
should be rect.maxX - rect.width / 4
maxX
/minX
are points in the rectangle, so it almost never makes sense to divide them.
func path(in rect: CGRect) -> Path {
return Path { path in
path.move(to: CGPoint(x: rect.minX + insetAmount, y: rect.midY))
path.addLine(to: CGPoint(x: rect.minX + rect.width / 4.0, y: rect.minY + insetAmount))
path.addLine(to: CGPoint(x: rect.maxX - rect.width / 4.0, y: rect.minY + insetAmount))
path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX - rect.width / 4.0, y: rect.maxY - insetAmount))
path.addLine(to: CGPoint(x: rect.minX + rect.width / 4.0, y: rect.maxY - insetAmount))
path.closeSubpath()
}
}
That said, I find the way this shape is insetted quite weird, the vertical parts insets "more" than the two sides. See this post for some ideas.