mcpField
S
swiftui-liquid-glass

swiftui-liquid-glass

github.com/dpearson2699デザイン・UI1.2k4.2k 回インストール13 週間前に更新
リポジトリ

swiftui-liquid-glass について

iOS 26以降でLiquid Glassを実装・レビューするSwiftUI開発者向けのスキルガイドです。コントロールやナビゲーション面、トランジション、アクセシビリティ、旧バージョン向けの代替表示を扱います。

主な機能

  1. 01Liquid Glass APIの使用法
  2. 02ガラスコンテナとブレンド
  3. 03モーフィングIDとトランジション
  4. 04ガラスボタンスタイル
  5. 05アクセシビリティと対応状況の確認

活用シーン

  1. 01フローティングコントロールへの適用
  2. 02ナビゲーションやコントロール背景の更新
  3. 03トランジションと操作性のレビュー
  4. 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 を使って新機能を実装する
  1. 対象となるサーフェス(フローティングコントロール、カスタムバー、一時的なコントロール)を特定します。
  2. 各要素の形状と目立ち具合を決め、実際のコントロールか静的なステータス表示かを判断します。
  3. グループ化されたグラス要素を GlassEffectContainer で囲みます。
  4. レイアウトおよび外観のモディファイアの後に .glassEffect() を適用します。
  5. タップまたはフォーカスが可能な要素にのみ .interactive() を追加します。
  6. アニメーションに伴ってビュー階層が変化する場合は、glassEffectID(_:in:) でモーフィングトランジションを追加します。glassEffectTransition(_:) は、常に存在するコンテナではなく、挿入または削除されるグラスの子要素に設定し、モーフィングとトランジションに従ってスタイルを選びます。
  7. if #available(iOS 26, *) で利用可能なバージョンを確認し、それ以前のバージョンにはフォールバックを用意します。
2. 既存の機能を Liquid Glass で改善する
  1. .glassEffect() に置き換えられるカスタムのコントロールまたはナビゲーションの背景を見つけます。
  2. ブレンドとパフォーマンスのため、兄弟関係にあるグラス要素を GlassEffectContainer で囲みます。
  3. グラス風のカスタムボタンを .buttonStyle(.glass)、.buttonStyle(.glassProminent)、または .buttonStyle(.glass(.clear)) などの設定可能なスタイルに置き換えます。ボタンに特定の色合いやバリアントが必要な場合は .glass(_:) を使用し、.glassProminent は強調度の高い主要なアクションに限って使用します。
  4. アニメーションによる挿入や削除が発生する箇所にモーフィングトランジションを追加します。
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 コード内にある。

参考資料

コメント