👔Swatch
可顯示一小塊展示區與名稱的色卡,但不止於顯示顏色,任何 view 都可以。

import SwiftUI
struct Swatch<V: View>: View {
// font: Avenir Next Condensed
let avenir = Font.custom("AvenirNextCondensed-Regular", size: 14)
let size: CGFloat // swatch size
let name: String // view name
let shadow: Color // border inner shadow
let border: Color // border color
let view: () -> V // swatch view
init(
name : String,
size : CGFloat = 80,
shadow : Color = .bg2, // 🌀 Color + system colors
border : Color = .bg3,
view: @escaping () -> V
){
self.size = size
self.name = name
self.shadow = shadow
self.border = border
self.view = view
}
var body: some View {
VStack(spacing: 0) {
// swatch view
view()
// ⭐️ overlay shadow + blend
.overlay {
Rectangle()
.fill(.white.shadow(.inner(
color: shadow, radius: 2, x: 2, y: -2
)))
// ⭐️ 必須用 .blendMode() 否則填充色會蓋住前景
.blendMode(.multiply)
}
.frame(width: size, height: size)
.border(border)
// swatch name
// 不要直接用 Text,否則會因為 Text 的長度不一而影響版面❗️
Rectangle()
.fill(.clear)
.frame(width: size, height: 20)
.overlay {
Text("\(name)")
.font(avenir)
.fixedSize() // ⭐️ no wrap
}
}
.padding(4)
.border(border)
}
}// Swatch<V>
// example
struct SwatchExample: View {
let colors = Color.standardColors.first(11) // 🌀 Array + .first(_ size:)
var body: some View {
VStack(spacing: 16) {
// colors
HStack(spacing: 12) { ForEach(colors, id: \.self) { color in
Swatch(name: color.name, border: .label4) { color } // 👔 custom view
}}
// gradient of colors
HStack(spacing: 12) { ForEach(colors, id: \.self) { color in
Swatch(name: "\(color.name).gradient", border: .label4) { color.gradient }
}}
}// VStack
}// body
}
// previews
struct Swatch_Previews: PreviewProvider {
static var previews: some View {
SwatchExample()
}
}
arr.first(): array first n elements
system colors: 色卡顏色來源
Last updated
Was this helpful?