WWDC Quick Look 💓 By SwiftGGTeam
iOS でブランドアイデンティティを伝える

iOS でブランドアイデンティティを伝える

元の動画を見る

ハイライト

Apple は iOS 26 の Liquid Glass デザイン体系において、App インターフェイスを UI レイヤーとコンテンツレイヤーに明確に分けました。ナビゲーションコントロールはネイティブのままにし、ブランドの個性はすべてコンテンツレイヤーで表現します。開発者はもう「iOS らしい」と「識別できる個性がある」の二択に悩む必要はありません。

主要内容

以前の問題:ブランド表現とネイティブ体験はいつも対立して見えた

多くの開発者はこの困境を経験しています。デザイナーはナビゲーションバーにブランドカラーを使い、TabBar を独自スタイルにしたいと言う。結果として、ユーザーは App を開いて戻るボタンを見つけるまで数秒かかります。クロスプラットフォームチームはさらに大変です。Web や Android のデザインをそのまま iOS に持ち込むと、ユーザーはいつも「何か違う」と感じます。(00:14

Apple の姿勢は明確です。iPhone ユーザーは、スマートフォン上の App が iOS らしく見えることを期待しています。目的は創造性を制限することではなく、認知負荷を減らすことです。ユーザーはあなたの iOS、Android、Web 版を同時に使っているわけではありません。手元の App が直感的に使えるかだけを気にしています。(01:20

iOS 26 の解決策:2 レイヤーモデル

Liquid Glass の導入は、App を 2 つのレイヤーとして捉えるという中心概念をもたらしました。

  • UI レイヤー:ナビゲーションバー、TabBar、ツールバー。ユーザーが道に迷わないようにする
  • コンテンツレイヤー:スクロールビュー内の画像、テキスト、データ可視化。App を唯一のものにする(02:36

ブランドを表現する最適な場所はコンテンツレイヤーです。UI レイヤーは土台として、ユーザーが操作方法を素早く理解できるようにします。

Gentler Streak はフィットネス App で、一見するとブランドイラストとデータチャートに満ちていて、強い個性があります。しかしナビゲーションをよく見ると、TabBar と上部ツールバーはすべてネイティブコンポーネントで、過度な改造はありません。(03:21

Slack は上部ツールバーをカスタマイズし、中央にチャンネル情報を表示するボタンを置いています。しかしボタンサイズ、フローティングアクションの位置、ポップオーバーの挙動は、すべてシステムコンポーネントと一貫しています。(04:12

Moonlitt は月相追跡 App で、TabBar がなく、インターフェイスは非常にミニマルです。月相カレンダーはカスタムコンポーネントですが、Liquid Glass 背景と、システム Sheet の同心円状のエッジを使い、ハードウェアの角丸と呼応しています。この App は唯一無二ですが、見た瞬間に iOS ネイティブだと分かります。(04:29

色:ナビゲーションバーからコンテンツ領域へ移す

iOS 26 以前、多くの App はナビゲーションバーや TabBar をブランドカラーで塗りつぶしていました。これらのコントロールは重く、コンテンツ領域を狭くします。(09:24

今の推奨は、色をコンテンツ領域、つまり ScrollView の中へ移すことです。Liquid Glass コントロールはコンテンツの上に浮かび、下にあるブランドカラーを動的に取り込みます。Slack は上部の単色ツールバーをコンテンツ領域に移し、スクロールに合わせて消えるようにしました。これによりコンテンツが画面全体を満たせます。(10:39

色は抑制して使います。階層、グルーピング、インタラクション状態を表すために使うべきで、画面全体を塗りつぶすためのものではありません。Slack は新着メッセージバッジ、新規メッセージボタン、TabBar 選択状態という重要な位置にだけ色を使っています。(10:16

カスタムフォントは Dynamic Type 対応が必須

Crumbl という App は独自設計の Crumbl Sans フォントを使い、マーケティングや App の大見出しに採用しています。しかしユーザーがシステム文字サイズを最大にしても、App は読みやすいままです。文字は折り返され、切り詰められません。(12:00

Dynamic Type はアクセシビリティ設定ですが、多くの人は日常的な好みとして使っています。Apple のシステムフォントにはこの能力が組み込まれています。カスタムフォントでは、開発者が自分で実装し、テストする必要があります。

Gentler Streak は完全にシステムフォントを使いながら、異なる字幅や SF Rounded のバリアントを組み合わせることで、豊かな階層感と識別性を両立しています。(13:53

アイコン:カスタムでも SF Symbols でもよい

NYT Cooking は独自のアイコンスタイルを使っています。エッジはやや鋭く、線画中心です。これらのアイコンは TabBar、ツールバー、コンテンツレイヤーで使われ、統一されていて簡潔で、小さいサイズでも明瞭です。(14:26

重要な細部があります。NYT Cooking の「共有」アイコンは、iOS、Android、Web でそれぞれ異なる 3 つのバージョンです。スタイルは統一されていますが、各プラットフォームではそのプラットフォームのユーザーになじみのある共有パターンに従っています。(14:58

すべての App にカスタムアイコンが必要なわけではありません。SF Symbols には現在 7,000 を超えるシンボルがあり、Xcode に組み込まれ、動的スケーリング、アクセシビリティ、ローカライズをサポートしています。デザイナーがアイコンライブラリを書き出す必要はなく、開発者はコードから直接呼び出せます。(15:23

Logo をナビゲーションバーに常駐させない

iOS の文脈では、ユーザーに自分がどの App を使っているかを常に思い出させる必要はありません。Logo は貴重な画面スペースを消費します。NYT Cooking はホーム画面にだけ Logo を表示し、スクロール時にフェードアウトさせます。この抑制はとても上品です。(15:59

詳細

カスタムフォントを Dynamic Type に対応させる

シナリオ:ブランドフォントを使いながら、ユーザーがシステム設定で文字サイズを大きくしてもレイアウトが壊れないようにする。

Text("今週の新フレーバー:チョコレートチップ")
    .font(.custom("CrumblSans-Bold", size: 24, relativeTo: .title))
    .lineLimit(nil)
    .fixedSize(horizontal: false, vertical: true)

要点:

  • relativeTo: .title はカスタムフォントをシステムの .title テキストスタイルに結びつけ、ユーザーがシステム文字サイズを調整したときに比例して拡大縮小されるようにします
  • lineLimit(nil) はスペース不足時に文字を切り詰めず、折り返しを許可します
  • .fixedSize(horizontal: false, vertical: true) は SwiftUI が複数行テキストの高さを正しく計算できるようにし、文字サイズ拡大後に切れないようにします

落とし穴:relativeTo を付けないとフォントサイズは固定になります。ロービジョンのユーザーが文字サイズを拡大したとき、文字が重なったり画面からはみ出したりします。

カスタムポップアップをシステム Context Menu で置き換える

シナリオ:手書きの長押しメニューをやめ、システム標準コンポーネントを使って、組み込みの変形アニメーションをそのまま得る。

struct MoonPhaseView: View {
    var body: some View {
        Image("moon_full")
            .resizable()
            .frame(width: 100, height: 100)
            .contextMenu {
                Button {
                    // 設定処理を行う
                } label: {
                    Label("月相設定", systemImage: "gearshape")
                }

                Button(role: .destructive) {
                    // 削除処理を行う
                } label: {
                    Label("観測を削除", systemImage: "trash")
                }
            }
    }
}

要点:

  • .contextMenu は SwiftUI ネイティブの修飾子であり、追加のジェスチャ認識実装は不要です
  • メニューはクリックされた要素から「成長」するように現れ、システム組み込みの morphing アニメーションを持ちます
  • role: .destructive により、削除項目は自動で赤く表示され、システム慣例に合います
  • Label と SF Symbols を組み合わせると、アイコンとテキストが自動で揃います

落とし穴:systemImage の代わりにカスタム Image を使う場合、サイズやベースラインが合っていないと変形アニメーションが不自然になります。できるだけ SF Symbols を使うか、カスタムアイコンを 24x24 と正しい baseline に厳密に合わせます。

Zoom Transition でコンテンツをつなぐ

シナリオ:リスト項目をタップして詳細ページへ入るとき、滑らかな遷移アニメーションで視覚的なつながりを作る。

struct RecipeListView: View {
    @Namespace private var animationNamespace

    var body: some View {
        NavigationStack {
            List(recipes) { recipe in
                NavigationLink(value: recipe) {
                    RecipeRow(recipe: recipe)
                        .matchedTransitionSource(id: recipe.id, in: animationNamespace)
                }
            }
            .navigationDestination(for: Recipe.self) { recipe in
                RecipeDetailView(recipe: recipe)
                    .navigationTransition(.zoom(sourceID: recipe.id, in: animationNamespace))
            }
        }
    }
}

要点:

  • matchedTransitionSource は遷移の起点となるビューをマークします
  • navigationTransition(.zoom(...)) は詳細ページ側で遷移アニメーションを定義します
  • ユーザーがタップしたリスト項目が滑らかに拡大して詳細ページになり、「どこから来たか」の関係が明確になります
  • この遷移は楽しいだけでなく、インタラクション効率も高めます

コンテンツ上部にブランドカラーを敷き、Liquid Glass に動的に拾わせる

シナリオ:ブランドカラーをナビゲーションバーから ScrollView 上部へ移し、浮かぶガラスコントロールに自然なブランド色を反映させる。

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 0) {
                // 上部に大きなブランドカラー領域を置き、Liquid Glass に下地色を提供する
                Rectangle()
                    .fill(brandGradient)
                    .frame(height: 200)

                // 実際のコンテンツ
                LazyVStack {
                    ForEach(items) { item in
                        ItemRow(item: item)
                    }
                }
            }
        }
    }

    var brandGradient: LinearGradient {
        LinearGradient(
            colors: [Color.purple.opacity(0.8), Color.blue.opacity(0.6)],
            startPoint: .top,
            endPoint: .bottom
        )
    }
}

要点:

  • 上部に十分な高さの色領域を置くと、Liquid Glass コントロールがその上に浮いたときに色を動的に屈折できます
  • 色が細かすぎたりコントラストが低すぎたりすると、ガラス効果が鈍く見えます
  • コンテンツ領域に大きなグラデーションを使うと、単色ブロックより奥行きが出ます

主要な学び

  • 全画面のグラデーション夜空をコンテンツ背景にした月相追跡 App を作る

    Moonlitt のやり方を参考に、コンテンツレイヤーを深い青から黒へのグラデーションで敷き詰め、夜空を表現します。中央には 3D 月相モデルを浮かべ、ユーザー位置に応じて動的に変化させます。ナビゲーションは極めてミニマルな単層構造にし、TabBar は不要です。Liquid Glass コントロールは夜空の深い青を自然に取り込み、インターフェイス全体が統一され没入感を持ちます。入口:SwiftUI の MeshGradient または LinearGradient で背景を作り、SceneKit または RealityKit で 3D 月相を描画します。

  • Zoom Transition でレシピ一覧と詳細をつなぐレシピ App を作る

    NYT Cooking を参考に、ユーザーが一覧ページの料理画像をタップすると、その画像が滑らかに拡大して詳細ページの先頭画像になります。コメント欄は下からスライドインします。戻るときは詳細ページが一覧内の元の位置へ縮みます。この遷移は「ブラウズから読む」切り替えを非常に連続的にします。入口:SwiftUI の matchedTransitionSourcenavigationTransition(.zoom)

  • 月次データが spring アニメーションで「生きる」フィットネスデータ App を作る

    Gentler Streak を参考に、月次振り返りページのスクロール時、各データカードを .spring(response: 0.4, dampingFraction: 0.7) で順に登場させます。運動種類は figure.runfigure.swim など、異なる SF Symbols バリアントで区別します。完全にシステムフォントを使い、字幅と字重の変化で階層を作ります。入口:SwiftUI の .scrollTransition または withAnimation(.spring)

  • カスタムフォントを「記憶に残る場所」だけで使うベーカリーブランド App を作る

    Crumbl を参考に、ブランドフォントを設計しても、大見出し、たとえば週替わりフレーバー名やマーケティングポップオーバーにだけ使います。本文、ボタン、ナビゲーションはすべて San Francisco にします。これによりブランドの記憶点を残しながら、可読性と Dynamic Type 対応を保てます。入口:.custom("BrandFont", relativeTo: .largeTitle) でシステムテキストスタイルに結びつけます。

  • ブランド配色でユーザーの記憶を強化するホーム画面 Widget を作る

    Crumbl の Widget を参考に、ユーザーが価値を感じるデータ、たとえば毎日の歩数、ToDo リスト、天気などを持つなら、柔らかい配色で識別性の高いホーム画面 Widget を提供します。Widget 自体に複雑なインタラクションは不要です。毎日ユーザーのホーム画面に現れること自体が、高頻度のブランド接触になります。入口:WidgetKitAppIntent。デザインでは App のコンテンツレイヤーと一貫した配色とアイコンスタイルを保ちます。

関連 Session

  • Principles of great design — AI 時代のデザイン責任に対する Apple の明確な安全ラインと、Agency と Forgiveness のインタラクション原則
  • SwiftUI — この Session で触れられた遷移やインタラクション効果を実装するための SwiftUI 新コントロールとアニメーション API
  • UIKit modernization — UIKit と SwiftUI を混在させる必要があるプロジェクトに向いた UIKit モダナイズ
  • Design principles — デザイン原則の深い展開であり、ブランド表現を補完する
  • AppKit modernization — ブランドを Apple プラットフォーム全体で一貫させる必要がある場合の macOS 側インターフェイスモダナイズ

コメント

GitHub Issues · utterances