Skip to content

Instantly share code, notes, and snippets.

@YusukeHosonuma
Created May 28, 2022 15:48
Show Gist options
  • Save YusukeHosonuma/ff97cebac37d54572fbb0761ed51e379 to your computer and use it in GitHub Desktop.
Save YusukeHosonuma/ff97cebac37d54572fbb0761ed51e379 to your computer and use it in GitHub Desktop.
Canvas で Apple ロゴっぽいレインボーなレンダリングをするやつ。
// 🌱 Inspired by and special thanks!
// https://gist.github.com/Koshimizu-Takehito/737381f5e55678e691205fe11fe16e93
import SwiftUI
struct ContentView: View {
var body: some View {
HStack(spacing: 12) {
ForEach(["applelogo", "swift"], id: \.self) { name in
VStack(spacing: 12) {
Group {
RainbowLogo(systemName: name)
.frame(width: 160, height: 160)
RainbowLogo(systemName: name)
.frame(width: 160, height: 120)
RainbowLogo(systemName: name)
.frame(width: 120, height: 160)
}
.border(.red)
}
}
}
}
}
private let colors: [Color] = [
.green,
.green,
.green,
.yellow,
.orange,
.red,
.purple,
.blue
]
struct RainbowLogo: View {
let systemName: String
@State private var ratio: CGFloat = 1.0
var body: some View {
ZStack {
Canvas { context, size in
let canvasRatio = size.width / size.height
//
// Compute frame of image.
//
let w: CGFloat
let h: CGFloat
if ratio > canvasRatio {
w = size.width
h = size.width * (1 / ratio)
} else {
w = size.height * ratio
h = size.height
}
let x: CGFloat = (size.width - w) / 2
let y: CGFloat = (size.height - h) / 2
//
// Clip to image.
//
context.clipToLayer { context in
let rect = CGRect(x: x, y: y, width: w, height: h)
context.draw(Image(systemName: systemName), in: rect)
}
//
// Render borders.
//
var rect = CGRect(x: x, y: y, width: w, height: h / CGFloat(colors.count))
for color in colors {
context.fill(Path(rect), with: .color(color))
rect.origin.y += rect.height
}
} symbols: {
Color.clear.frame(width: ratio) // ☑️ Invalidates canvas by `ratio` was changed.
}
//
// Get ratio of image. (not rendered)
//
Image(systemName: systemName)
.hidden()
.readSize {
ratio = $0.width / $0.height
}
}
}
}
extension View {
func readSize(perform: @escaping (CGSize) -> ()) -> some View {
self.background(
GeometryReader { geometry in
Color.clear
.preference(key: SizeKey.self, value: geometry.size)
}
)
.onPreferenceChange(SizeKey.self, perform: perform)
}
}
struct SizeKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
@YusukeHosonuma
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment