液態玻璃設計系統 (iOS 26) 是做什麼的?
用於實作 Apple 液態玻璃 (Liquid Glass) 的模式—一種動態材質,能模糊其背後內容、反射周圍色彩與光線,並對觸控與指標互動做出反應。涵蓋 SwiftUI、UIKit 與 WidgetKit 的整合。
啟用時機
- 使用新版設計語言建構或更新 iOS 26+ 的應用程式
- 實作玻璃風格的按鈕、卡片、工具列或容器
- 在玻璃元件之間建立變形過渡動畫
- 對 Widget 套用液態玻璃效果
- 將現有的模糊/材質效果遷移至新的液態玻璃 API
核心模式 — SwiftUI
基本玻璃效果
為任何視圖加入液態玻璃最簡單的方式:
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect() // 預設:一般變體,膠囊形狀
自訂形狀與色調
Text("Hello, World!")
.font(.title)
.padding()
.glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 16.0))
關鍵自訂選項:
.regular— 標準玻璃效果.tint(Color)— 加入色調以提升顯著性.interactive()— 對觸控與指標互動做出反應- 形狀:
.capsule(預設)、.rect(cornerRadius:)、.circle
玻璃按鈕樣式
Button("Click Me") { /* action */ }
.buttonStyle(.glass)
Button("Important") { /* action */ }
.buttonStyle(.glassProminent)
用於多個元件的 GlassEffectContainer
為確保效能與變形能力,務必將多個玻璃視圖包裹在容器中:
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.font(.system(size: 36))
.glassEffect()
}
}
spacing 參數控制合併距離 — 距離越近的元件會將它們的玻璃形狀融合在一起。
合併玻璃效果
使用 glassEffectUnion 將多個視圖組合成單一玻璃形狀:
@Namespace private var namespace
GlassEffectContainer(spacing: 20.0) {
HStack(spacing: 20.0) {
ForEach(symbolSet.indices, id: \.self) { item in
Image(systemName: symbolSet[item])
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectUnion(id: item < 2 ? "group1" : "group2", namespace: namespace)
}
}
}
變形過渡
在玻璃元件出現/消失時建立流暢的變形:
@State private var isExpanded = false
@Namespace private var namespace
GlassEffectContainer(spacing: 40.0) {
HStack(spacing: 40.0) {
Image(systemName: "scribble.variable")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("pencil", in: namespace)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80.0, height: 80.0)
.glassEffect()
.glassEffectID("eraser", in: namespace)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
將水平捲動延伸至側邊欄下方
若要允許水平捲動內容延伸到側邊欄或檢查器下方,請確保 ScrollView 的內容達到容器的前緣/尾緣。當佈局延伸到邊緣時,系統會自動處理側邊欄下方的捲動行為 — 不需要額外的修飾符。
核心模式 — UIKit
基本 UIGlassEffect
let glassEffect = UIGlassEffect()
glassEffect.tintColor = UIColor.systemBlue.withAlphaComponent(0.3)
glassEffect.isInteractive = true
let visualEffectView = UIVisualEffectView(effect: glassEffect)
visualEffectView.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.layer.cornerRadius = 20
visualEffectView.clipsToBounds = true
view.addSubview(visualEffectView)
NSLayoutConstraint.activate([
visualEffectView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
visualEffectView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
visualEffectView.widthAnchor.constraint(equalToConstant: 200),
visualEffectView.heightAnchor.constraint(equalToConstant: 120)
])
// 將內容加入 contentView
let label = UILabel()
label.text = "Liquid Glass"
label.translatesAutoresizingMaskIntoConstraints = false
visualEffectView.contentView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: visualEffectView.contentView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: visualEffectView.contentView.centerYAnchor)
])
用於多個元件的 UIGlassContainerEffect
let containerEffect = UIGlassContainerEffect()
containerEffect.spacing = 40.0
let containerView = UIVisualEffectView(effect: containerEffect)
let firstGlass = UIVisualEffectView(effect: UIGlassEffect())
let secondGlass = UIVisualEffectView(effect: UIGlassEffect())
containerView.contentView.addSubview(firstGlass)
containerView.contentView.addSubview(secondGlass)
捲動邊緣效果
scrollView.topEdgeEffect.style = .automatic
scrollView.bottomEdgeEffect.style = .hard
scrollView.leftEdgeEffect.isHidden = true
工具列玻璃整合
let favoriteButton = UIBarButtonItem(image: UIImage(systemName: "heart"), style: .plain, target: self, action: #selector(favoriteAction))
favoriteButton.hidesSharedBackground = true // 選擇退出共享玻璃背景
核心模式 — WidgetKit
渲染模式偵測
struct MyWidgetView: View {
@Environment(\.widgetRenderingMode) var renderingMode
var body: some View {
if renderingMode == .accented {
// 強調色模式:白色調色、主題玻璃背景
} else {
// 全彩模式:標準外觀
}
}
}
用於視覺階層的強調色群組
HStack {
VStack(alignment: .leading) {
Text("Title")
.widgetAccentable() // 強調色群組
Text("Subtitle")
// 主要群組(預設)
}
Image(systemName: "star.fill")
.widgetAccentable() // 強調色群組
}
強調色模式中的圖片渲染
Image("myImage")
.widgetAccentedRenderingMode(.monochrome)
容器背景
VStack { /* content */ }
.containerBackground(for: .widget) {
Color.blue.opacity(0.2)
}
關鍵設計決策
| 決策 | 理由 |
|---|---|
| 使用 GlassEffectContainer 包裹 | 效能最佳化,啟用玻璃元件間的變形 |
spacing 參數 | 控制合併距離 — 微調元件需多近才能融合 |
@Namespace + glassEffectID | 在視圖階層變更時啟用流暢的變形過渡 |
interactive() 修飾符 | 明確選擇加入觸控/指標反應 — 並非所有玻璃都應回應 |
| UIKit 中的 UIGlassContainerEffect | 與 SwiftUI 相同的容器模式,以維持一致性 |
| Widget 中的強調色渲染模式 | 當使用者選擇強調色的主畫面時,系統會套用調色玻璃 |
最佳實踐
- 務必使用 GlassEffectContainer — 當對多個同層視圖套用玻璃效果時,啟用變形並改善渲染效能
- 在其他外觀修飾符(frame、font、padding)之後套用
.glassEffect() - 僅在會回應使用者互動的元件上(按鈕、可切換項目)使用
.interactive() - 在容器中仔細選擇間距以控制玻璃效果的合併時機
- 變更視圖階層時使用
withAnimation以啟用流暢的變形過渡 - 在不同外觀下測試 — 淺色模式、深色模式以及強調色/調色模式
- 確保無障礙對比度 — 玻璃上的文字必須保持可讀
應避免的反模式
- 在沒有 GlassEffectContainer 的情況下使用多個獨立的
.glassEffect()視圖 - 巢狀太多玻璃效果 — 會降低效能與視覺清晰度
- 對每個視圖都套用玻璃效果 — 保留給互動式元件、工具列與卡片使用
- 在 UIKit 中使用圓角時忘記設定
clipsToBounds = true - 忽略 Widget 中的強調色渲染模式 — 會破壞強調色主畫面的外觀
- 在玻璃後面使用不透明背景 — 會破壞半透明效果
使用時機
- 使用 iOS 26 新版設計的導覽列、工具列與標籤列
- 浮動動作按鈕與卡片式容器
- 需要視覺深度與觸控回饋的互動控制項
- 應與系統液態玻璃外觀整合的 Widget
- 相關 UI 狀態之間的變形過渡