Skip to content

Instantly share code, notes, and snippets.

@CodeSlicing
Last active February 12, 2022 20:47
Show Gist options
  • Save CodeSlicing/bc32584f746c7de4b6d2f17c03b65087 to your computer and use it in GitHub Desktop.
Save CodeSlicing/bc32584f746c7de4b6d2f17c03b65087 to your computer and use it in GitHub Desktop.
Source code for CodeSlicing episode demonstrating how PureSwiftUI can clean up the Apple tutorial on drawing paths and shapes
//
// MountainBadge.swift
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright © 2020 Adam Fordyce. All rights reserved.
//
import PureSwiftUI
private let mountainLayoutConfig = LayoutGuideConfig.grid(
columns: [0, 0.24, 0.3, 0.5, 0.7, 0.76, 1],
rows: [0, 0.265, 0.465, 0.523, 0.552, 0.638, 1])
private let backgroundLayoutConfig =
LayoutGuideConfig.polar(rings: [0.9, 1], segments: 72)
struct MountainBadge: View {
var body: some View {
GeometryReaderStack { (geo: GeometryProxy) in
ZStack {
BackgroundShape()
.fill(LinearGradient([
(.rgb8(239, 120, 221), 0),
(.rgb8(239, 172, 120), 0.6),
], to: .bottom))
.layoutGuide(backgroundLayoutConfig, color: .red, lineWidth: 1)
ForEach(0..<8) { index in
MountainShape()
.scale(0.34)
.fillColor(.rgb8(79, 79, 191))
.yOffset(-geo.minDimension * 0.218)
.rotate(45.degrees * index)
}
.opacity(0.5)
}
.frame(geo.minDimension)
}
}
}
private struct MountainShape: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
let g = mountainLayoutConfig.layout(in: rect)
.scaled(0.5, anchor: .bottom)
.rotated(90.degrees, anchor: .bottom)
// mountain base
path.shape([
g.bottomLeading,
g[1, 5],
g[3, 3],
g[5, 5],
g.bottomTrailing
])
// mountain peak
path.shape([
g[2, 4],
g[3, 1],
g[4, 4],
g[3, 2]
])
}
}
}
private struct MountainShapeWithRectCoordinates: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
// mountain base
path.shape([
rect.bottomLeading,
rect[0.24, 0.638],
rect[0.5, 0.523],
rect[0.76, 0.638],
rect.bottomTrailing
])
// mountain peak
path.shape([
rect[0.3, 0.552],
rect[0.5, 0.265],
rect[0.7, 0.552],
rect[0.5, 0.465]
])
}
}
}
private struct MountainShapeWithRelativeLayoutCoordinates: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
let g = LayoutGuide.grid(rect, columns: 1, rows: 1)
// mountain base
path.shape([
g.bottomLeading,
g[rel: 0.24, rel: 0.638],
g[rel: 0.5, rel: 0.523],
g[rel: 0.76, rel: 0.638],
g.bottomTrailing
])
// mountain peak
path.shape([
g[rel: 0.3, rel: 0.552],
g[rel: 0.5, rel: 0.265],
g[rel: 0.7, rel: 0.552],
g[rel: 0.5, rel: 0.465]
])
}
}
}
private struct BackgroundShape: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
let p = backgroundLayoutConfig.layout(in: rect)
path.shape([
p[1, 0],
p[0, 13],
p[0, 23],
p[1, 36],
p[0, 49],
p[0, 59],
], cornerRadius: rect.widthScaled(0.15))
}
}
}
struct DrawingPathsAndShapesTest01_Previews: PreviewProvider {
struct DrawingPathsAndShapesTest01_Harness: View {
var body: some View {
VStack {
Group {
MountainBadge()
.layoutGuide(backgroundLayoutConfig)
Image("drawingpathsandshapes.mountain.badge")
.resizedToFill()
}
.frame(400)
}
.ignoresSafeArea()
}
}
static var previews: some View {
DrawingPathsAndShapesTest01_Harness()
.showLayoutGuides(true)
.previewDevice(.iPhone_12_Pro_Max)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment