swiftui-liquid-glass について
iOS 26以降でLiquid Glassを実装・レビューするSwiftUI開発者向けのスキルガイドです。コントロールやナビゲーション面、トランジション、アクセシビリティ、旧バージョン向けの代替表示を扱います。
主な機能
- 01Liquid Glass APIの使用法
- 02ガラスコンテナとブレンド
- 03モーフィングIDとトランジション
- 04ガラスボタンスタイル
- 05アクセシビリティと対応状況の確認
活用シーン
- 01フローティングコントロールへの適用
- 02ナビゲーションやコントロール背景の更新
- 03トランジションと操作性のレビュー
- 04旧バージョンとアクセシビリティ対応の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill swiftui-liquid-glassインストール後、Claude Code で/swiftui-liquid-glassを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/liquid-glass.md
詳細
SwiftUI Liquid Glass
Liquid Glass は、Apple プラットフォーム 26 全体に導入された、動的な半透明マテリアルです。現在の SDK でビルドすると、標準の SwiftUI バーとプレゼンテーションには自動的に適用されます。カスタムのグラスは、一般的なコンテンツの背景ではなく、機能的なコントロールやナビゲーション用のサーフェスに使用してください。
追加の例を含む API リファレンス全体については、references/liquid-glass.md を参照してください。
目次
ワークフロー
依頼に合った方法を選択してください。
1. Liquid Glass を使って新機能を実装する
- 対象となるサーフェス(フローティングコントロール、カスタムバー、一時的なコントロール)を特定します。
- 各要素の形状と目立ち具合を決め、実際のコントロールか静的なステータス表示かを判断します。
- グループ化されたグラス要素を
GlassEffectContainerで囲みます。 - レイアウトおよび外観のモディファイアの後に
.glassEffect()を適用します。 - タップまたはフォーカスが可能な要素にのみ
.interactive()を追加します。 - アニメーションに伴ってビュー階層が変化する場合は、
glassEffectID(_:in:)でモーフィングトランジションを追加します。glassEffectTransition(_:)は、常に存在するコンテナではなく、挿入または削除されるグラスの子要素に設定し、モーフィングとトランジションに従ってスタイルを選びます。 if #available(iOS 26, *)で利用可能なバージョンを確認し、それ以前のバージョンにはフォールバックを用意します。
2. 既存の機能を Liquid Glass で改善する
.glassEffect()に置き換えられるカスタムのコントロールまたはナビゲーションの背景を見つけます。- ブレンドとパフォーマンスのため、兄弟関係にあるグラス要素を
GlassEffectContainerで囲みます。 - グラス風のカスタムボタンを
.buttonStyle(.glass)、.buttonStyle(.glassProminent)、または.buttonStyle(.glass(.clear))などの設定可能なスタイルに置き換えます。ボタンに特定の色合いやバリアントが必要な場合は.glass(_:)を使用し、.glassProminentは強調度の高い主要なアクションに限って使用します。 - アニメーションによる挿入や削除が発生する箇所にモーフィングトランジションを追加します。
3. 既存の Liquid Glass の使用をレビューする
コンテンツとコントロールの所有関係、レイアウト順序、コンテナの適用範囲、インタラクティブ性、トランジション、利用可能なバージョン、アクセシビリティ設定、フォールバックについて、それぞれのエフェクトを確認します。修正するたびに同じ UI フィクスチャを復元し、チェックリストを再実行します。
コア API の概要
glassEffect(_:in:)
ビューの背後に Liquid Glass を適用します。デフォルトは、Capsule 形状の .regular バリアントです。
nonisolated func glassEffect(
_ glass: Glass = .regular,
in shape: some Shape = DefaultGlassEffectShape()
) -> some View
Glass 構造体
| プロパティ/メソッド | 目的 |
|---|---|
.regular | 標準のグラスマテリアル |
.clear | 透明なバリアント。読みやすさを確保する必要がある場合は、暗めの処理やコントラストの調整を加えます |
.identity | 視覚効果なし(そのまま通過) |
.tint(_:) | 目立たせるために色合いを加えます |
.interactive(_:) | タッチやポインターの操作に反応します |
連結して使用します:.regular.tint(.blue).interactive()
GlassEffectContainer
複数のグラスビューを囲み、描画、ブレンド、モーフィングを共有します。
GlassEffectContainer(spacing: 24) {
// child views with .glassEffect()
}
spacing は、近くにあるグラス形状がブレンドを開始する距離を制御します。アニメーションによるトランジション中に形状が融合し、静止時には分離した状態を保てるよう、内部レイアウトの間隔と同じか、それ以上に設定します。
モーフィングとトランジション
| モディファイア | 目的 |
|---|---|
glassEffectID(_:in:) | ビュー階層の変更時にモーフィングするための安定した識別子 |
glassEffectUnion(id:namespace:) | 複数のビューを一つのグラス形状に統合 |
glassEffectTransition(_:) | グラスの表示/非表示の方法を制御 |
トランジションの選択:コンテナの間隔内にある近接したエフェクトには .matchedGeometry を使用します。離れた場所への挿入/削除、またはジオメトリを一致させない場合は .materialize を使用します。トランジションアニメーションが不要な場合に限り .identity を使用します。
ボタンスタイル
Button("Action") { }
.buttonStyle(.glass) // standard glass button
Button("Primary") { }
.buttonStyle(.glassProminent) // prominent glass button
Button("Media") { }
.buttonStyle(.glass(.clear)) // configurable variant; verify contrast
関連する iOS 26 API
| API | 用途 |
|---|---|
scrollEdgeEffectStyle | スクロール境界の視覚的な処理を設定します。 |
backgroundExtensionEffect | ミラーリングされたぼかしを使って、安全領域の端まで背景を延長します。 |
ToolbarSpacer | ツールバー項目の間に視覚的な区切りを作ります。 |
シグネチャと使用例については、 references/liquid-glass.md の該当するセクションを参照してください。
コード例
利用可能性チェック付きのガラスボタン
if #available(iOS 26, *) {
Button("Show Status") { showStatusDetails() }
.buttonStyle(.glass)
} else {
Button("Show Status") { showStatusDetails() }
.buttonStyle(.bordered)
}
コンテナ内でグループ化されたガラス形状
let symbols = ["pencil", "eraser.fill", "lasso"]
GlassEffectContainer(spacing: 24) {
HStack(spacing: 24) {
ForEach(symbols, id: \.self) { symbol in
Image(systemName: symbol)
.frame(width: 56, height: 56)
.glassEffect()
}
}
}
近接するビュー間のモーフィングトランジション
@State private var isExpanded = false
@Namespace private var ns
var body: some View {
GlassEffectContainer(spacing: 40) {
HStack(spacing: 40) {
Image(systemName: "pencil")
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectID("pencil", in: ns)
if isExpanded {
Image(systemName: "eraser.fill")
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectID("eraser", in: ns)
.glassEffectTransition(.matchedGeometry)
}
}
}
Button("Toggle") {
withAnimation { isExpanded.toggle() }
}
.buttonStyle(.glass)
}
ビューを結合して単一のガラス形状にする
@Namespace private var ns
GlassEffectContainer(spacing: 20) {
HStack(spacing: 20) {
ForEach(items.indices, id: \.self) { i in
Image(systemName: items[i])
.frame(width: 80, height: 80)
.glassEffect()
.glassEffectUnion(id: i < 2 ? "group1" : "group2", namespace: ns)
}
}
}
色合いを付けたガラスアイコンコントロール
struct GlassIconControl: View {
let icon: String
let tint: Color
let action: () -> Void
var body: some View {
Button(action: action) {
Image(systemName: icon)
.font(.title2)
.padding()
}
.buttonStyle(.glass(.regular.tint(tint)))
}
}
明るいコンテンツ上に配置するクリアガラスのアクション
if #available(iOS 26, *) {
ZStack {
Capsule()
.fill(.black.opacity(0.28))
Button {
playRecap()
} label: {
Label("Play", systemImage: "play.fill")
.font(.headline)
.padding(.horizontal, 8)
}
.buttonStyle(.glass(.clear))
}
.fixedSize()
} else {
Button("Play", systemImage: "play.fill") { playRecap() }
.buttonStyle(.borderedProminent)
}
クリアガラスを使うのは、背景上でもラベルや記号を読み取れる場合に限ってください。 明るい背景や複雑な背景では、控えめな暗転レイヤーを追加するか、より不透明な ボタンスタイルを選択してください。
ツールバーコントロールではない静的なステータス件数
VStack(spacing: 8) {
Text("24")
.font(.headline.monospacedDigit())
.accessibilityLabel("24 options expiring")
Text("Options Expiring")
.font(.subheadline)
.foregroundStyle(.secondary)
}
// Keep read-only status out of toolbar control slots and do not add .interactive().
よくある間違い
| 間違い | 修正方法 |
|---|---|
| 静的なコンテンツにガラスを適用する | コントロール/ナビゲーションレイヤー内で使用してください。 |
読み取り専用のステータスに .interactive() やアクションスロットを使う | ステータスをコンテンツとして表示するか、バッジ全体を実際のアクセシブルなアクションにしてください。 |
| 関連するエフェクトにネストされたコンテナを使う | 関連するブレンド/モーフィングのグループごとに、GlassEffectContainer を1つ使用してください。 |
パディング/フレーム/スタイルより前に .glassEffect() を適用する | まずレイアウトと外観を適用し、その後にガラスを適用してください。 |
| カスタムエフェクトでデフォルトのアクセシビリティ設定を想定する | 透明度を下げる、視差効果を減らす、コントラスト、視認性をテストしてください。 |
| iOS 26 より前のフォールバックがない | エフェクトを利用可能な場合に限定し、機能するフォールバックを維持してください。 |
レビューチェックリスト
- 利用可能性:
if #available(iOS 26, *)があり、フォールバック UI が用意されている。 - コンテナ:複数のガラスビューが
GlassEffectContainerで囲まれている。 - モディファイアの順序:
.glassEffect()がレイアウト/外観モディファイアの後に適用されている。 - インタラクティブ性:
.interactive()がユーザー操作のある箇所でのみ使われている。 - ステータスとアクション:静的な件数/ステータスがツールバーコントロールになっておらず、押下/ホバーのアフォーダンスを示していない。
- トランジション:モーフィングアニメーションで
@NamespaceとともにglassEffectIDが使われている。 - トランジションの種類:近接するエフェクトには
.matchedGeometry、離れたエフェクトには.materializeが使われ、条件付きのガラス子ビューに適用されている。 - 一貫性:関連する要素全体で、形状、色合い、間隔が統一されている。
- パフォーマンス:ガラスエフェクトの数が抑えられ、グループ化にコンテナが使われている。
- アクセシビリティ:透明度を下げる機能と視差効果を減らす機能を有効にしてテストされている。
- ボタンスタイル:ボタンには標準の
.glass、.glassProminent、または設定可能な.glass(_:)が使われている。色合い付きまたはクリアのバリアントが必要な場合は、.glass(_:)を優先する。 - クリアガラスのコントラスト:明るいコンテンツ上のクリアガラスに、暗転/コントラスト処理が施されているか、より視認性の高いスタイルが使われている。
- 並行処理:
glassEffectID/glassEffectUnionに渡す ID がSendableであり、MainActor が注釈された Liquid Glass API が SwiftUI の UI コード内にある。
参考資料
- API ガイド全文:references/liquid-glass.md
- Apple のドキュメント:カスタムビューへの Liquid Glass の適用
- Apple のドキュメント:Liquid Glass の採用