ハイライト
Franck は Landmarks サンプルプロジェクトを使って、Xcode 26 SDK 環境下で SwiftUI アプリを再構築する方法をデモンストレーションしました。App 構造、Toolbars、Search、Controls、そしてカスタム Liquid Glass の 5 つの側面における変更をカバーしています。
主要内容
新しい SDK がリリースされるたび、開発者が最も恐れるのは「見た目は良くなったけど、コードを一から書き直さなければならない」という状況です。今回の iOS 26 / macOS Tahoe での Liquid Glass 導入でも、最初はそう思いがちです。sidebar がガラス素材になり、tab bar が浮き上がり、ボタンがカプセル形状になった——既存の toolbar、sheet、button をすべて書き直す必要があるのでしょうか?
Franck の答えはこうです。まず Xcode 26 で再ビルドして、何が無料で手に入るかを確認してから、コードを書くかどうかを決めましょう。彼は実際の Landmarks サンプルアプリを使って一通り説明しました——hero 画像が sidebar で切り取られてしまう、toolbar 上の 5 つのボタンの視覚的な優先順位が判別できない、検索ボックスの配置位置が iPhone と iPad で不一致になるといった問題です。これらは旧 API では手動で適応コードを書く必要がありましたが、新しい SDK では 1〜2 行の modifier で解決できます。backgroundExtensionEffect で画像を自動的に safe area の外に延伸させ、ToolbarSpacer で toolbar item を意味的にグループ化し、searchable を NavigationSplitView に配置すれば、iPhone の下部と iPad の上部 trailing に自動的に適応されます。デモ全体のロジックは非常に明確です。自動的に得られる改善を先に取り入れ、残りの意味表現が必要な場合だけ新しい API を記述します。
詳細
App 構造:sidebar はデフォルトで Liquid Glass になり、コンテンツの上に浮きます。sidebar が hero 画像を切り取ってしまう場合、backgroundExtensionEffect を使って画像を safe area の外までミラー延伸させます(03:59)。
// Extend background images
struct LandmarkDetailView: View {
let landmark: Landmark
var body: some View {
ScrollView {
VStack {
Image(landmark.backgroundImageName)
.resizable()
.aspectRatio(contentMode: .fill)
.backgroundExtensionEffect()
}
}
}
}
ポイント:
.backgroundExtensionEffect()は画像が safe area の外でミラー表示されぼかしが入るようにし、元のコンテンツは safe area 内に表示されたままにします。- sidebar の幅を手動で計算したり、画像を再トリミングする必要はありません。sidebar を非表示にすると、ミラー領域が自動的に拡張されていることが確認できます。
TabView の tab bar は iPhone でフローティングスタイルになり、スクロール時に収納するよう設定でき、上部に accessory(Music の再生バーのような)を配置できます(05:39)。
// Tab bar accessory
TabView {
// tabs
}
.tabBarMinimizeBehavior(.onScrollDown)
.tabViewBottomAccessory {
MusicPlaybackView()
}
struct MusicPlaybackView: View {
@Environment(\.tabViewBottomAccessoryPlacement)
var placement
var body: some View {
if placement == .inline {
// compact layout
} else {
// full layout
}
}
}
ポイント:
tabBarMinimizeBehavior(.onScrollDown)は、下方向スクロール時に tab bar を収納し、上方向スクロール時に復元します。tabViewBottomAccessoryは tab bar の上に常駐 view を配置し、bar 収納時に空いたスペースを活用します。- 環境値
tabViewBottomAccessoryPlacementで.inline(収納時のインライン配置)と展開時の 2 つのレイアウトを区別します。
Toolbars:item は自動的にグループ化され、ToolbarSpacer で意味的な境界を明示的に制御します(08:26)。
// Visually separate toolbar items
struct LandmarkDetailView: View {
var body: some View {
ScrollView {
ScrollContent()
}
.toolbar {
ToolbarItem { ShareLink() }
ToolbarSpacer(.fixed)
ToolbarItem { FavoriteButton() }
ToolbarItem { CollectionsButton() }
ToolbarSpacer(.fixed)
ToolbarItem { InspectorToggle() }
}
}
}
ポイント:
- デフォルトでは隣接する
ToolbarItemは同じ glass 背景グループにマージされます。 ToolbarSpacer(.fixed)で背景グループを強制的に分割し、favorite / collections を単独のグループに、share と inspector をそれぞれ独立させます。ToolbarSpacer(.flexible, placement: .bottomBar)で leading/trailing 方向の伸長も可能です(Mail の filter と compose が bottomBar の両端に配置されるように)。- 単一の item を背景グループから独立させたい場合(アバターなど)は
.sharedBackgroundVisibility(.hidden)を使用。item にバッジを付けたい場合は.badge(count)を使います。
Search:searchable を NavigationSplitView に配置すると、システムは iPhone では自動的に下部に、iPad/Mac では上部 trailing に配置します(11:44)。
// Search in the top-trailing position
struct TopTrailingSearch: View {
@State private var searchText = ""
var body: some View {
NavigationSplitView {
SidebarContent()
} detail: {
DetailContent()
}
.searchable(text: $searchText)
}
}
ポイント:
searchableをNavigationSplitViewに配置することは、検索が特定の列ではなくビュー全体に作用することを示します。- iPhone フォーマットでは検索ボックスが自動的に画面下部に移動し、親指で到達しやすくなります。iPad/Mac では自動的に toolbar の trailing に配置されます。
- 複数 tab のアプリで専用の検索ページを作りたい場合:
Tab(role: .search) { ... }+searchableをTabViewに配置。ユーザーがその tab に切り替えると、検索ボックスが tab bar を置き換えます。 - toolbar button として強制的に最小化したい場合は、
.searchToolbarBehavior(.minimize)を使います。
Controls:ボタンはデフォルトでカプセル形状(小さいサイズの macOS では角丸矩形のまま)。新しい .glass / .glassProminent スタイルが追加されました(15:33)。
// Prominent glass button
Button("Get Started") { }
.buttonStyle(.glassProminent)
// Standard glass button
Button("Learn More") { }
.buttonStyle(.glass)
ポイント:
.glassProminentは行動喚起(CTA)に使用し、自動的に tint が付きます。.glassは通常の glass ボタンで、背景は下層コンテンツに応じて適応します。- Slider に tick marks(
stepに基づいて自動生成)とneutralValue(0 点のオフセットを指定、EQ のような双方向値用)が追加されました。 .rect(corner: .containerConcentric)で角の同心円を作成し、角丸半径を手動で計算する手間を省けます。
カスタム Liquid Glass:任意の view に .glassEffect() を追加。複数の要素は GlassEffectContainer で組み合わせて morphing を実現します(19:51)。
// GlassEffectContainer
@Namespace var namespace
GlassEffectContainer {
VStack {
if isExpanded {
VStack(spacing: 16) {
ForEach(badges) { badge in
BadgeLabel(badge: badge)
.glassEffect()
.glassEffectID(badge.id, in: namespace)
}
}
}
BadgeToggle()
.buttonStyle(.glass)
.glassEffectID("badgeToggle", in: namespace)
}
}
ポイント:
GlassEffectContainerは内部の複数の glass 要素がサンプリング領域を共有し、各要素が独立してサンプリングすることによる視覚的な不整合を回避します。glassEffectIDと同一の@Namespaceを組み合わせることで、展開/収納時に要素間で流体 morph 遷移が発生します。- 単一の要素には
.glassEffect(.regular.tint(.green))で着色、.glassEffect(.regular.interactive())で押下時にガラスが縮小してハイライトする効果を追加できます。
重要ポイント
-
やるべきこと:まずプロジェクトを Xcode 26 で再ビルドし、どの UI が自動的に良くなり、哪些が壊れたかを記録してください。
- なぜやるべきか:多くの新効果(toolbar グループ化、sheet 埋め込み glass、scroll edge effect)はコードなしで得られます。一度通すだけで移作業の半分を省けます。
- どう始めるか:新規ブランチで Xcode 26 に切り替え、各主要ページを build & run して、視覚的な変化のスクリーンショット比較を review ドキュメントにまとめ、問題リストに基づいてどの API を操作するかを決定します。
-
やるべきこと:旧バージョンで toolbar/sheet のデフォルトスタイルに対抗するために追加した hack(カスタム背景、半透明マスク、
presentationBackground)をクリアしてください。- なぜやるべきか:新デザインの automatic scroll edge effect と Liquid Glass マテリアルはこれらの旧 hack と干渉し合い、残せば残すほど視覚的に悪化します。
- どう始めるか:プロジェクト内で
presentationBackground、.background(.regularMaterial)、カスタムColor.black.opacityなどを検索し、削除してデフォルト効果を確認できるかを逐一評価します。
-
やるべきこと:toolbar item を意味的に再グループ化し、
ToolbarSpacer(.fixed)で明示的に表現してください。- なぜやるべきか:ユーザーは新デザインで glass 背景の連続性からどのボタンが同じグループかを判断します(「favorite + add to collection」は一組、share と inspector はそれぞれ独立)。意味的な不透明なツールバーはユーザーの誤操作を招きます。
- どう始めるか:各ページの toolbar の全ボタンをリスト化し、「関連するアクション」で括弧付け;各グループ間に
ToolbarSpacer(.fixed)を挿入;グループから外れる item には.sharedBackgroundVisibility(.hidden)を追加。
-
やるべきこと:
searchableをNavigationSplitViewの階層に引き上げ、iPhone/iPad 用の二重レイアウトを削除してください。- なぜやるべきか:システムは iPhone で自動的に検索ボックスを下部に、iPad/Mac で toolbar trailing に配置し、一つのコードで両端に対応します。
- どう始めるか:既存の
searchableを detail 列からNavigationSplitViewの外側に移動;検索が中核機能でない場合は.searchToolbarBehavior(.minimize)を追加して自動収納を有効にします。
-
やるべきこと:自作コントロールの外層で
glassEffect+GlassEffectContainerを試し、手書きのカードスタイルを置き換えられるか確認してください。- なぜやるべきか:カスタムコントロールに glass を被せるとシステムコンポーネントと視覚的に統一でき、
GlassEffectContainerが提供する fluid morphing は手書きアニメーションでは実現が困難です。 - どう始めるか:「展開/収納」インタラクションを持つ自作コンポーネント(フローティングツールバー、絵文字パネルなど)を一つ選び、各サブ要素に
glassEffectIDを追加、外層をGlassEffectContainerで包み、新旧アニメーション効果を比較します。
- なぜやるべきか:カスタムコントロールに glass を被せるとシステムコンポーネントと視覚的に統一でき、
関連セッション
- Meet Liquid Glass — Liquid Glass マテリアルの設計原理と光学特性の紹介。
- Get to know the new design system — 全プラットフォーム新デザインシステムのベストプラクティスと使用ルール。
- Build a UIKit app with the new design — UIKit 側の同テーマ移行ガイド。本記事と対照して読めます。
- Better together: SwiftUI and RealityKit — visionOS 26 で SwiftUI と RealityKit を併用する新しい方法。
- Make a big impact with small writing changes — 新デザイン下でのコピー微調整が体験に与える増幅効果。
コメント
GitHub Issues · utterances