Created
May 28, 2022 15:48
-
-
Save YusukeHosonuma/ff97cebac37d54572fbb0761ed51e379 to your computer and use it in GitHub Desktop.
Canvas で Apple ロゴっぽいレインボーなレンダリングをするやつ。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 🌱 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() | |
} | |
} |
Author
YusukeHosonuma
commented
May 28, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment