ButtonUp, ButtonDown 📦
用來當作 Tab Bar Button 彈起與按下的兩個狀態,這兩個只是單純的 View 而已,還不能真的按。

import SwiftUI
import ViewModifiers
public struct ButtonUp: View {
// button properties
let size: CGFloat // icon size
let icon: String // icon name (SF Symbol)
// public init
public init(icon: String, size: CGFloat = 32){
self.icon = icon
self.size = size
}
// button body
public var body: some View {
ZStack {
// 1. 用漸層為底紙,遮在圖示下面
Neu.buttonUpIconBackground
.frame(width: size, height: size) // 這個大小只夠遮住 icon
// 2. 再鋪上挖洞的方紙
Rectangle()
.foregroundColor(Neu.color.cardBackground) // 上色
.frame(width: size * 2, height: size * 2) // 方紙為圖示的兩倍大
.inverseMask(IconCard(icon, size: size)) // 以圖示挖洞
// shadow & highlight
.shadow(color: Neu.color.iconShadow, radius: 6, x: 6, y: 6)
.shadow(color: .white, radius: 3, x: -3, y: -3)
.cornerRadius(size * 0.5) // 剪圓角
} // container (ZStack)
// ⭐️ 合併所有圖層(為了幫整個 ZStack 製作陰影)
.compositingGroup()
// ⭐️ 讓打光與陰影都「收斂」一點(radius 大,x y 小)
.shadow(color: Color.white.opacity(0.9), radius: 4, x: -2, y: -2)
.shadow(color: Neu.color.iconShadow.opacity(0.9), radius: 4, x: 2, y: 2)
}
}
import SwiftUI
import ViewModifiers // for `.inverseMask`
import Workaround // for `SystemImage`
public struct ButtonDown: View {
// button properties
let size: CGFloat // icon size
let icon: String // icon name (SF Symbol)
// public init
public init(icon: String, size: CGFloat = 32){
self.icon = icon
self.size = size
}
// button body
public var body: some View {
// 0.5 - 0.125 = 0.375
let rimMask = Rectangle().cornerRadius(size * 0.375).padding(size * 0.125)
// ⭐️ container
return ZStack {
// 1. 鋪上放大一點的圓角方紙
Rectangle()
.foregroundColor(Neu.color.cardBackground) // 上色
.frame(width: size * 2.25, height: size * 2.25) // 方紙為圖示的 2.25 倍
.cornerRadius(size * 0.5) // 剪圓角
// 2. 設計「按下按鈕」的陰影效果
Rectangle()
// 2-1. 紙張上色、放大一點、剪圓角
.fill(Neu.buttonDownShadow) // 上色
.frame(width: size * 2.25, height: size * 2.25) // 方紙為圖示的 2.25 倍
.cornerRadius(size * 0.5) // 剪圓角
// 2-2. 剪下圓角邊緣 (padding = 0.125 * size)
.inverseMask(rimMask)
// 2-3. 打光、下陰影
.shadow(color: Neu.color.iconShadow, radius: 6, x: 6, y: 6)
.shadow(color: .white, radius: 6, x: -4, y: -4)
// 2-4. 剪掉外圍陰影
.cornerRadius(size * 0.5)
// 3. 圖示
Gradient.bottomRight(.black, .purple, .pink, .yellow) // 準備圖示顏色
.frame(width: size, height: size) // 限制圖示大小
.mask(SystemImage(icon)) // 剪下圖示的部分
.font(.system(size: 24, weight: .bold)) // 字體加粗
.offset(x: 2, y: 2) // ⭐️ 稍微往右下角移動,「按下的效果」更好
} // container (ZStack)
}
}
Last updated
Was this helpful?