リキッドガラスデザインシステム (iOS 26) は何をしますか?
Appleの「リキッドガラス」を実装するためのパターン集です。リキッドガラスは、背後にあるコンテンツをブラーし、周囲の色や光を反射し、タッチやポインターの操作に反応する動的なマテリアルです。SwiftUI、UIKit、WidgetKitの統合をカバーします。
いつ有効化するか
- iOS 26+向けのアプリを新しいデザイン言語で構築または更新する場合
- ガラススタイルのボタン、カード、ツールバー、コンテナを実装する場合
- ガラス要素間のモーフィングトランジションを作成する場合
- ウィジェットにリキッドガラスエフェクトを適用する場合
- 既存のブラー/マテリアルエフェクトを新しいリキッドガラス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") { /* アクション */ }
.buttonStyle(.glass)
Button("Important") { /* アクション */ }
.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 を使用して、複数のビューを1つのガラス形状に結合します:
@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 { /* コンテンツ */ }
.containerBackground(for: .widget) {
Color.blue.opacity(0.2)
}
主要な設計判断
| 判断 | 根拠 |
|---|---|
| GlassEffectContainerでラップ | パフォーマンス最適化、ガラス要素間のモーフィングを有効化 |
spacing パラメータ | 結合距離を制御 — 要素がブレンドするために必要な近さを微調整 |
@Namespace + glassEffectID | ビュー階層の変更時にスムーズなモーフィングトランジションを有効化 |
interactive() モディファイア | タッチ/ポインター反応への明示的なオプトイン — すべてのガラスが応答する必要はない |
| UIKitのUIGlassContainerEffect | 一貫性のためにSwiftUIと同じコンテナパターン |
| ウィジェットのアクセントレンダリングモード | ユーザーがティントホーム画面を選択したときに、システムがティントガラスを適用 |
ベストプラクティス
- 複数の兄弟ビューにガラスを適用する場合は、常にGlassEffectContainerを使用する — モーフィングを有効にし、レンダリングパフォーマンスを向上させます
.glassEffect()は他の外観モディファイア(frame、font、padding)の後に適用する- ユーザー操作に応答する要素(ボタン、切り替え可能な項目)にのみ
.interactive()を使用する - コンテナ内のspacingを慎重に選択して、ガラスエフェクトが結合するタイミングを制御する
- ビュー階層を変更するときは
withAnimationを使用して、スムーズなモーフィングトランジションを有効にする - ライトモード、ダークモード、アクセント/ティントモードでテストする
- アクセシビリティのコントラストを確保する — ガラス上のテキストは読みやすさを維持する必要があります
避けるべきアンチパターン
- GlassEffectContainerなしで複数の独立した
.glassEffect()ビューを使用する - ガラスエフェクトをネストしすぎる — パフォーマンスと視覚的な明瞭性を損なう
- すべてのビューにガラスを適用する — インタラクティブな要素、ツールバー、カードに限定する
- UIKitで角丸を使用するときに
clipsToBounds = trueを忘れる - ウィジェットでアクセントレンダリングモードを無視する — ティントホーム画面の外観が崩れる
- ガラスの背後に不透明な背景を使用する — 半透明効果が無効になる
いつ使用するか
- 新しいiOS 26デザインのナビゲーションバー、ツールバー、タブバー
- フローティングアクションボタンとカードスタイルのコンテナ
- 視覚的な奥行きとタッチフィードバックが必要なインタラクティブコントロール
- システムのリキッドガラス外観と統合する必要があるウィジェット
- 関連するUI状態間のモーフィングトランジション