Token导航 LogoToken导航

Agent Skill · 研究检索

axiom-swiftui-nav-ref(Axiom Swiftui 导航参考)

axiom-swiftui-nav-ref 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

axiom-swiftui-nav-ref 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 22,159。

总安装 4,633周安装 199GitHub Stars 873下载 1,624核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:axiom-swiftui-nav-ref(Axiom Swiftui 导航参考)
来源仓库:https://github.com/charleswiltgen/axiom
仓库路径:skills/axiom-swiftui-nav-ref
安装命令:
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-swiftui-nav-ref
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-swiftui-nav-ref

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

axiom-swiftui-nav-ref 汇总 SwiftUI 导航 API 演进历程与接口规范,从 iOS 16 到 26 版本全覆盖。适用于查询 NavigationPath、Tab/Sidebar 融合等新特性的参数说明与行为差异。

包含 Liquid Glass 设计语言在导航中的视觉实现细节,适合高版本系统集成参考。内容侧重 API 本身,不涉及导航架构决策建议,相关指引请见 axiom-swiftui-nav。注意部分高级功能仅限特定设备或系统版本可用,部署前需做兼容性校验。

来源仓库内路径:skills/axiom-swiftui-nav-ref

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-swiftui-nav…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

axiom-swiftui-nav-ref 怎么安装?

在终端执行 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-swiftui-nav-ref。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

axiom-swiftui-nav-ref 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

axiom-swiftui-nav-ref 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

axiom-swiftui-nav-ref 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

axiom-swiftui-nav-ref 用的人多吗?

公开数据是累计安装 4,633 次,近一周安装 199 次,下载 1,624 次,GitHub 873 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

axiom-swiftui-nav-ref 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
axiom-swiftui-nav-ref

Axiom Swiftui 导航参考 · 本页

4,633873需要联网MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

SwiftUI Navigation API Reference

Overview

SwiftUI's navigation APIs provide data-driven, programmatic navigation that scales from simple stacks to complex multi-column layouts. Introduced in iOS 16 (2022) with NavigationStack and NavigationSplitView, evolved in iOS 18 (2024) with Tab/Sidebar unification, and refined in iOS 26 (2025) with Liquid Glass design.

Evolution timeline
  • 2022 (iOS 16) NavigationStack, NavigationSplitView, NavigationPath, value-based NavigationLink
  • 2024 (iOS 18) Tab/Sidebar unification, sidebarAdaptable style, zoom navigation transition
  • 2025 (iOS 26) Liquid Glass navigation chrome, bottom-aligned search, floating tab bars, backgroundExtensionEffect
Key capabilities
  • Data-driven navigation NavigationPath represents stack state, enabling programmatic push/pop and deep linking
  • Multi-column layouts NavigationSplitView adapts automatically (3-column on iPad → single stack on iPhone)
  • State restoration Codable NavigationPath + SceneStorage for persistence across app launches
  • Tab integration Per-tab NavigationStack with state preservation on tab switch (iOS 18+)
  • Liquid Glass Automatic glass navigation bars, sidebars, and toolbars (iOS 26+)
When to use vs UIKit
  • SwiftUI navigation New apps, multiplatform, simpler navigation flows → Use NavigationStack/SplitView
  • UINavigationController Complex coordinator patterns, legacy code, specific UIKit features → Consider UIKit
Related Skills
  • Use axiom-swiftui-nav for anti-patterns, decision trees, pressure scenarios
  • Use axiom-swiftui-nav-diag for systematic troubleshooting of navigation issues

When to Use This Skill

Use this skill when:

  • Implementing navigation APIs NavigationStack, NavigationSplitView, NavigationPath, Tab+Navigation
  • Deep linking or state restoration URL routing, Codable NavigationPath, SceneStorage
  • Adopting iOS 26+ features Liquid Glass navigation, bottom-aligned search, tab bar minimization
  • Choosing navigation architecture Stack vs SplitView vs coordinator patterns

API Evolution

Timeline

YeariOS VersionKey Features
2020iOS 14NavigationView (deprecated iOS 16)
2022iOS 16NavigationStack, NavigationSplitView, NavigationPath, value-based NavigationLink
2024iOS 18Tab/Sidebar unification, sidebarAdaptable, TabSection, zoom transitions
2025iOS 26Liquid Glass navigation, backgroundExtensionEffect, tabBarMinimizeBehavior

NavigationView (Deprecated)

NavigationView is deprecated as of iOS 16. Use NavigationStack (single-column push/pop) or NavigationSplitView (multi-column) exclusively in new code. Key improvements: single NavigationPath replaces per-link isActive bindings, value-based type safety, built-in Codable state restoration. See "Migrating to new navigation types" documentation.


NavigationStack Complete Reference

NavigationStack represents a push-pop interface like Settings on iPhone or System Settings on macOS.

1.1 Creating NavigationStack

Basic NavigationStack
NavigationStack {
    List(Category.allCases) { category in
        NavigationLink(category.name, value: category)
    }
    .navigationTitle("Categories")
    .navigationDestination(for: Category.self) { category in
        CategoryDetail(category: category)
    }
}
With Path Binding (WWDC 2022, 6:05)
struct PushableStack: View {
    @State private var path: [Recipe] = []
    @StateObject private var dataModel = DataModel()

    var body: some View {
        NavigationStack(path: $path) {
            List(Category.allCases) { category in
                Section(category.localizedName) {
                    ForEach(dataModel.recipes(in: category)) { recipe in
                        NavigationLink(recipe.name, value: recipe)
                    }
                }
            }
            .navigationTitle("Categories")
            .navigationDestination(for: Recipe.self) { recipe in
                RecipeDetail(recipe: recipe)
            }
        }
        .environmentObject(dataModel)
    }
}

Path binding + value-presenting NavigationLink + navigationDestination(for:) form the core data-driven navigation pattern.

1.2 NavigationLink (Value-Based)

Value-presenting NavigationLink
// Correct: Value-based (iOS 16+)
NavigationLink(recipe.name, value: recipe)

// Correct: With custom label
NavigationLink(value: recipe) {
    RecipeTile(recipe: recipe)
}

// Deprecated: View-based (iOS 13-15)
NavigationLink(recipe.name) {
    RecipeDetail(recipe: recipe)  // Don't use in new code
}
How NavigationLink works with NavigationStack
  1. NavigationStack maintains a path collection
  2. Tapping a value-presenting link appends the value to the path
  3. NavigationStack maps navigationDestination modifiers over path values
  4. Views are pushed onto the stack based on destination mappings

1.3 navigationDestination Modifier

Single Type
.navigationDestination(for: Recipe.self) { recipe in
    RecipeDetail(recipe: recipe)
}
Multiple Types
NavigationStack(path: $path) {
    RootView()
        .navigationDestination(for: Recipe.self) { recipe in
            RecipeDetail(recipe: recipe)
        }
        .navigationDestination(for: Category.self) { category in
            CategoryList(category: category)
        }
        .navigationDestination(for: Chef.self) { chef in
            ChefProfile(chef: chef)
        }
}
Navigation Anti-Patterns
  • Never mix navigationDestination(for:) and NavigationLink(destination:) in the same NavigationStack hierarchy — causes undefined behavior
  • Register navigationDestination(for:) once per data type — duplicates cause the wrong view to appear
Placement rules
  • Place navigationDestination outside lazy containers (not inside ForEach)
  • Place near related NavigationLinks for code organization
  • Must be inside NavigationStack hierarchy
// Correct: Outside lazy container
ScrollView {
    LazyVGrid(columns: columns) {
        ForEach(recipes) { recipe in
            NavigationLink(value: recipe) {
                RecipeTile(recipe: recipe)
            }
        }
    }
}
.navigationDestination(for: Recipe.self) { recipe in
    RecipeDetail(recipe: recipe)
}

// Wrong: Inside ForEach (may not be loaded)
ForEach(recipes) { recipe in
    NavigationLink(value: recipe) { RecipeTile(recipe: recipe) }
        .navigationDestination(for: Recipe.self) { r in  // Don't do this
            RecipeDetail(recipe: r)
        }
}

1.4 NavigationPath

NavigationPath is a type-erased collection for heterogeneous navigation stacks.

Typed Array vs NavigationPath
// Typed array: All values same type
@State private var path: [Recipe] = []

// NavigationPath: Mixed types
@State private var path = NavigationPath()
NavigationPath Operations
// Append value
path.append(recipe)

// Pop to previous
path.removeLast()

// Pop to root
path.removeLast(path.count)
// or
path = NavigationPath()

// Check count
if path.count > 0 { ... }

// Deep link: Set multiple values
path.append(category)
path.append(recipe)
Codable Support
// NavigationPath is Codable when all values are Codable
@State private var path = NavigationPath()

// Encode
let data = try JSONEncoder().encode(path.codable)

// Decode
let codableRep = try JSONDecoder().decode(NavigationPath.CodableRepresentation.self, from: data)
path = NavigationPath(codableRep)

NavigationSplitView Complete Reference

NavigationSplitView creates multi-column layouts that adapt to device size.

2.1 Two-Column Layout

Basic Two-Column (WWDC 2022, 10:40)
struct MultipleColumns: View {
    @State private var selectedCategory: Category?
    @State private var selectedRecipe: Recipe?
    @StateObject private var dataModel = DataModel()

    var body: some View {
        NavigationSplitView {
            List(Category.allCases, selection: $selectedCategory) { category in
                NavigationLink(category.localizedName, value: category)
            }
            .navigationTitle("Categories")
        } detail: {
            if let recipe = selectedRecipe {
                RecipeDetail(recipe: recipe)
            } else {
                Text("Select a recipe")
            }
        }
    }
}

2.2 Three-Column Layout

Add a content: closure between sidebar and detail for a middle column:

NavigationSplitView {
    List(Category.allCases, selection: $selectedCategory) { category in
        NavigationLink(category.localizedName, value: category)
    }
} content: {
    List(dataModel.recipes(in: selectedCategory), selection: $selectedRecipe) { recipe in
        NavigationLink(recipe.name, value: recipe)
    }
} detail: {
    RecipeDetail(recipe: selectedRecipe)
}

2.3 NavigationSplitView with NavigationStack

Place a NavigationStack(path:) inside the detail column for grid-to-detail drill-down while preserving sidebar selection:

NavigationSplitView {
    List(Category.allCases, selection: $selectedCategory) { ... }
} detail: {
    NavigationStack(path: $path) {
        RecipeGrid(category: selectedCategory)
            .navigationDestination(for: Recipe.self) { recipe in
                RecipeDetail(recipe: recipe)
            }
    }
}

2.4 Column Visibility

@State private var columnVisibility: NavigationSplitViewVisibility = .all

NavigationSplitView(columnVisibility: $columnVisibility) {
    Sidebar()
} content: {
    Content()
} detail: {
    Detail()
}

// Programmatically control visibility
columnVisibility = .detailOnly  // Hide sidebar and content
columnVisibility = .all          // Show all columns
columnVisibility = .automatic    // System decides

2.5 Automatic Adaptation

NavigationSplitView automatically adapts:

  • iPad landscape All columns visible (depending on configuration)
  • iPad portrait/Slide Over Collapses to overlay or single column
  • iPhone Single navigation stack
  • Apple Watch/TV Single navigation stack

Selection changes automatically translate to push/pop on iPhone.

2.6 iOS 26+ Liquid Glass Sidebar (WWDC 2025, 323)

NavigationSplitView {
    List { ... }
} detail: {
    DetailView()
}
// Sidebar automatically gets Liquid Glass appearance on iPad/macOS

// Extend content behind glass sidebar
.backgroundExtensionEffect()  // Mirrors and blurs content outside safe area

Deep Linking and URL Routing

3.1 Deep Link Pattern

Use .onOpenURL to receive URLs, parse with URLComponents, then manipulate NavigationPath:

.onOpenURL { url in
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
          let host = components.host else { return }
    path.removeLast(path.count)  // Pop to root first
    // Parse host/path to determine destination, then path.append(value)
}

For multi-step deep links (myapp://category/desserts/recipe/apple-pie), iterate URL path components and append each resolved value to build the full navigation stack.

For comprehensive deep linking examples, error diagnosis, and testing workflows, see axiom-swiftui-nav-diag (Pattern 3).


State Restoration

4.1 Complete State Restoration (WWDC 2022, 18:12)

struct UseSceneStorage: View {
    @StateObject private var navModel = NavigationModel()
    @SceneStorage("navigation") private var data: Data?
    @StateObject private var dataModel = DataModel()

    var body: some View {
        NavigationSplitView {
            List(Category.allCases, selection: $navModel.selectedCategory) { category in
                NavigationLink(category.localizedName, value: category)
            }
            .navigationTitle("Categories")
        } detail: {
            NavigationStack(path: $navModel.recipePath) {
                RecipeGrid(category: navModel.selectedCategory)
            }
        }
        .task {
            // Restore on appear
            if let data = data {
                navModel.jsonData = data
            }
            // Save on changes
            for await _ in navModel.objectWillChangeSequence {
                data = navModel.jsonData
            }
        }
        .environmentObject(dataModel)
    }
}

4.2 Codable NavigationModel

class NavigationModel: ObservableObject, Codable {
    @Published var selectedCategory: Category?
    @Published var recipePath: [Recipe] = []

    enum CodingKeys: String, CodingKey {
        case selectedCategory
        case recipePathIds  // Store IDs, not full objects
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeIfPresent(selectedCategory, forKey: .selectedCategory)
        try container.encode(recipePath.map(\.id), forKey: .recipePathIds)
    }

    init() {}

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.selectedCategory = try container.decodeIfPresent(Category.self, forKey: .selectedCategory)
        let recipePathIds = try container.decode([Recipe.ID].self, forKey: .recipePathIds)
        self.recipePath = recipePathIds.compactMap { DataModel.shared[$0] } // Discard deleted items
    }
}

Store IDs (not full model objects) and use compactMap to handle deleted items gracefully. Add jsonData computed property and objectWillChangeSequence for SceneStorage integration as shown in 4.1.


Tab + Navigation Integration

5.1 Tab Syntax (iOS 18+) (WWDC 2024, 4:27)

TabView {
    Tab("Watch Now", systemImage: "play") {
        WatchNowView()
    }
    Tab("Library", systemImage: "books.vertical") {
        LibraryView()
    }
    Tab(role: .search) {
        NavigationStack {
            SearchView()
                .navigationTitle("Search")
        }
        .searchable(text: $searchText)
    }
}

Search tab requirement: Contents of a search-role tab must be wrapped in NavigationStack with .searchable() applied to the stack. Without NavigationStack, the search field will not appear. For foundational .searchable patterns (suggestions, scopes, tokens, programmatic control), see axiom-swiftui-search-ref.

5.2 TabView with NavigationStack Per Tab

TabView {
    Tab("Home", systemImage: "house") {
        NavigationStack {
            HomeView()
                .navigationDestination(for: Item.self) { item in
                    ItemDetail(item: item)
                }
        }
    }
    Tab("Settings", systemImage: "gear") {
        NavigationStack {
            SettingsView()
        }
    }
}

Each tab has its own NavigationStack to preserve navigation state when switching tabs.

5.3 Sidebar-Adaptable TabView (WWDC 2024, 6:41)

TabView {
    Tab("Watch Now", systemImage: "play") {
        WatchNowView()
    }
    Tab("Library", systemImage: "books.vertical") {
        LibraryView()
    }
    TabSection("Collections") {
        Tab("Cinematic Shots", systemImage: "list.and.film") {
            CinematicShotsView()
        }
        Tab("Forest Life", systemImage: "list.and.film") {
            ForestLifeView()
        }
    }
    TabSection("Animations") {
        // More tabs...
    }
    Tab(role: .search) {
        SearchView()
    }
}
.tabViewStyle(.sidebarAdaptable)

TabSection creates sidebar groups. .sidebarAdaptable enables sidebar on iPad, tab bar on iPhone. Search tab with .search role gets special placement.

5.4 Tab Customization (WWDC 2024, 10:45)

@AppStorage("MyTabViewCustomization")
private var customization: TabViewCustomization

TabView {
    Tab("Watch Now", systemImage: "play", value: .watchNow) {
        WatchNowView()
    }
    .customizationID("Tab.watchNow")
    .customizationBehavior(.disabled, for: .sidebar, .tabBar)  // Can't be hidden

    Tab("Optional Tab", systemImage: "star", value: .optional) {
        OptionalView()
    }
    .customizationID("Tab.optional")
    .defaultVisibility(.hidden, for: .tabBar)  // Hidden by default
}
.tabViewCustomization($customization)

5.5 Tab Context Menus

Use .contextMenu(menuItems:) on a Tab to add a context menu to its sidebar representation (e.g., right-click on Mac, long-press on iPad sidebar).

Tab("Currently Reading", systemImage: "book") {
    CurrentBooksList()
}
.contextMenu {
    Button {
        pinnedTabs.insert(.reading)
    } label: {
        Label("Pin", systemImage: "pin")
    }
    Button {
        showShareSheet = true
    } label: {
        Label("Share", systemImage: "square.and.arrow.up")
    }
}

Return an empty closure to deactivate the context menu conditionally:

.contextMenu {
    if canPin {
        Button("Pin", systemImage: "pin") { pin() }
    }
}
iPhone Tab Bar Long-Press

.contextMenu on Tab only applies to the sidebar representation (iPad/Mac). iPhone tab bar context menus require UIKit interop (adding UILongPressGestureRecognizer to UITabBar via Introspect or a UITabBarController subclass). See axiom-swiftui-nav-diag for workaround patterns.

Caveat: Relies on private UITabBarButton subviews — fragile across iOS versions, not a public API guarantee.

5.6 Programmatic Tab Visibility

Use .hidden(_:) to show/hide tabs based on app state while preserving their navigation state.

State-Driven Tab Visibility
Tab("Libraries", systemImage: "square.stack") { LibrariesView() }
    .hidden(context == .browse)  // Hide based on app state

Apply .hidden(condition) to each tab. Tabs hidden this way preserve their navigation state (unlike conditional if rendering which destroys and recreates them).

State Preservation

Key difference: .hidden(_:) preserves tab state, conditional rendering does not.

// ✅ State preserved when hidden
Tab("Settings", systemImage: "gear") {
    SettingsView()  // Navigation stack preserved
}
.hidden(!showSettings)

// ❌ State lost when condition changes
if showSettings {
    Tab("Settings", systemImage: "gear") {
        SettingsView()  // Navigation stack recreated
    }
}
Common Patterns
Tab("Beta Features", systemImage: "flask") { BetaView() }
    .hidden(!UserDefaults.standard.bool(forKey: "enableBetaFeatures"))

Same pattern applies to authentication state, purchase status, and debug builds — bind .hidden() to any boolean condition.

Animated Transitions

Wrap state changes in withAnimation for smooth tab bar layout transitions:

Button("Switch to Browse") {
    withAnimation {
        context = .browse
        selection = .tracks  // Switch to first visible tab
    }
}
// Tab bar animates as tabs appear/disappear
// Uses system motion curves automatically

5.7 iOS 26+ Tab Features (WWDC 2025, 256)

// Tab bar minimization on scroll
TabView { ... }
    .tabBarMinimizeBehavior(.onScrollDown)

// Bottom accessory view (always visible)
TabView { ... }
    .tabViewBottomAccessory {
        PlaybackControls()
    }

// Dynamic visibility (recommended for mini-players)
// ⚠️ Requires iOS 26.1+ (not 26.0)
TabView { ... }
    .tabViewBottomAccessory(isEnabled: showMiniPlayer) {
        MiniPlayerView()
            .transition(.opacity)
    }
// isEnabled: true = shows accessory
// isEnabled: false = hides AND removes reserved space

// Search tab with dedicated search field
Tab(role: .search) {
    NavigationStack {
        SearchView()
            .navigationTitle("Search")
    }
    .searchable(text: $searchText)
}
// Morphs into search field when selected
// ⚠️ NavigationStack wrapper required for search field to appear
// Fallback: If no tab has .search role, the tab view applies search
// to ALL tabs, resetting search state when the selected tab changes
Dynamic Bottom Accessory

The accessory can switch on activeTab for per-tab content, though Apple's usage (Music mini-player) keeps it global. Read @Environment(\.tabViewBottomAccessoryPlacement) to adapt layout: .bar when above tab bar (full controls), other values when inline with collapsed tab bar (compact).

Reserve tabViewBottomAccessory for cross-tab content (playback, status). For tab-specific actions, prefer floating glass buttons within the tab's content view.

5.8 Tab API Quick Reference

ModifierTargetiOSPurpose
Tab(_:systemImage:value:content:)—18+New tab syntax with selection value
Tab(role:.search)—18+Semantic search tab with morph behavior
TabSection(_:content:)—18+Group tabs in sidebar view
.contextMenu(menuItems:)Tab18+Add context menu to tab's sidebar representation
.customizationID(_:)Tab18+Enable user customization
.customizationBehavior(_:for:)Tab18+Control hide/reorder permissions
.defaultVisibility(_:for:)Tab18+Set initial visibility state
.hidden(_:)Tab18+Programmatic visibility with state preservation
.tabViewStyle(.sidebarAdaptable)TabView18+Sidebar on iPad, tabs on iPhone
.tabViewCustomization($binding)TabView18+Persist user tab arrangement
.tabBarMinimizeBehavior(_:)TabView26+Auto-hide on scroll
.tabViewBottomAccessory(isEnabled:content:)TabView26.1+Dynamic content below tab bar

iOS 26+ Navigation Features

6.1 Liquid Glass Navigation (WWDC 2025, 323)

Automatic adoption when building with Xcode 26:

  • Navigation bars become Liquid Glass
  • Sidebars float above content with glass effect
  • Tab bars float with new compact appearance
  • Toolbars get automatic grouping

6.2 Background Extension Effect

NavigationSplitView {
    Sidebar()
} detail: {
    HeroImage()
        .backgroundExtensionEffect()  // Content extends behind sidebar
}

6.3 Bottom-Aligned Search (WWDC 2025, 256)

Foundational search APIs For .searchable, isSearching, suggestions, scopes, tokens, and programmatic control, see axiom-swiftui-search-ref. This section covers iOS 26 bottom-aligned refinement only.

NavigationSplitView {
    Sidebar()
} detail: {
    DetailView()
}
.searchable(text: $query, prompt: "What are you looking for?")
// Automatically bottom-aligned on iPhone, top-trailing on iPad

6.4 Scroll Edge Effect

// Automatic blur effect when content scrolls under toolbar
// Remove any custom darkening backgrounds - they interfere

// For dense UIs, adjust sharpness
ScrollView { ... }
    .scrollEdgeEffectStyle(.soft)  // .sharp, .soft

6.5 Sheet Presentations with Zoom Transition

In iOS 26, sheets can morph directly out of the buttons that present them. Make the presenting toolbar item a source for a navigation zoom transition, and mark the sheet content as the destination:

@Namespace private var namespace

// Sheet morphs out of presenting button
.toolbar {
    ToolbarItem {
        Button("Settings") { showSettings = true }
            .matchedTransitionSource(id: "settings", in: namespace)
    }
}
.sheet(isPresented: $showSettings) {
    SettingsView()
        .navigationTransition(.zoom(sourceID: "settings", in: namespace))
}

Other presentations also flow smoothly out of Liquid Glass controls — menus, alerts, and popovers. Dialogs automatically morph out of the buttons that present them without additional code.

Audit tip: If you've used presentationBackground to apply custom backgrounds to sheets, consider removing it and let the new Liquid Glass sheet material shine. Partial height sheets are now inset with glass background by default.

6.6 Toolbar Morphing Transitions

iOS 26 automatically morphs toolbars during NavigationStack push/pop when each destination view declares its own .toolbar {}. Items with matching toolbar(id:) and ToolbarItem(id:) IDs stay stable during the transition (no bounce), while unmatched items animate in/out.

Key rule: Attach .toolbar {} to individual views inside NavigationStack, not to NavigationStack itself. Otherwise there is nothing to morph between.

See axiom-swiftui-26-ref skill for complete toolbar morphing API including DefaultToolbarItem, toolbar(id:) stable items, ToolbarSpacer patterns, and troubleshooting.


Router/Coordinator Patterns

7.1 When to Use Coordinators

Use coordinators when:

  • Navigation logic is complex with conditional flows
  • Testing navigation in isolation
  • Sharing navigation logic across multiple screens
  • UIKit interop with heavy navigation requirements

Use built-in navigation when:

  • Simple linear or hierarchical navigation
  • State restoration is primary concern
  • Fewer than 5-10 navigation destinations
  • No need for navigation unit testing

7.2 Simple Router Pattern

// Route enum defines all possible destinations
enum AppRoute: Hashable {
    case home
    case category(Category)
    case recipe(Recipe)
    case settings
}

// Router class manages navigation
@Observable
class Router {
    var path = NavigationPath()

    func navigate(to route: AppRoute) {
        path.append(route)
    }

    func popToRoot() {
        path.removeLast(path.count)
    }

    func pop() {
        if !path.isEmpty {
            path.removeLast()
        }
    }
}

// Usage in views
struct ContentView: View {
    @State private var router = Router()

    var body: some View {
        NavigationStack(path: $router.path) {
            HomeView()
                .navigationDestination(for: AppRoute.self) { route in
                    switch route {
                    case .home:
                        HomeView()
                    case .category(let category):
                        CategoryView(category: category)
                    case .recipe(let recipe):
                        RecipeDetail(recipe: recipe)
                    case .settings:
                        SettingsView()
                    }
                }
        }
        .environment(router)
    }
}

// In child views
struct RecipeCard: View {
    let recipe: Recipe
    @Environment(Router.self) private var router

    var body: some View {
        Button(recipe.name) {
            router.navigate(to: .recipe(recipe))
        }
    }
}

7.3 Coordinator Pattern with Protocol

For larger apps, extract a Coordinator protocol with associatedtype Route: Hashable and var path: NavigationPath. Each feature area gets its own coordinator conformance with domain-specific routes and convenience methods (e.g., showRecipeOfTheDay() that resets path and navigates).

7.4 Testing Navigation

// Router is easily testable
func testNavigateToRecipe() {
    let router = Router()
    let recipe = Recipe(name: "Apple Pie")

    router.navigate(to: .recipe(recipe))

    XCTAssertEqual(router.path.count, 1)
}

func testPopToRoot() {
    let router = Router()
    router.navigate(to: .category(.desserts))
    router.navigate(to: .recipe(Recipe(name: "Apple Pie")))

    router.popToRoot()

    XCTAssertTrue(router.path.isEmpty)
}

Testing Checklist

  • Deep links navigate correctly from cold start AND while running
  • Pop to root clears entire stack
  • State restores on app relaunch (SceneStorage key unique per scene)
  • Deleted items handled gracefully in restoration (compactMap)
  • NavigationSplitView collapses correctly on iPhone (selection pushes)
  • iOS 26+: Liquid Glass appearance, bottom-aligned search, tab bar minimization

API Quick Reference

NavigationStack

NavigationStack { content }
NavigationStack(path: $path) { content }

NavigationSplitView

NavigationSplitView { sidebar } detail: { detail }
NavigationSplitView { sidebar } content: { content } detail: { detail }
NavigationSplitView(columnVisibility: $visibility) { ... }

NavigationLink

NavigationLink(title, value: value)
NavigationLink(value: value) { label }

NavigationPath

path.append(value)
path.removeLast()
path.removeLast(path.count)
path.count
path.codable  // For encoding
NavigationPath(codableRepresentation)  // For decoding

Modifiers

.navigationTitle("Title")
.navigationDestination(for: Type.self) { value in View }
.searchable(text: $query)
.tabViewStyle(.sidebarAdaptable)
.tabBarMinimizeBehavior(.onScrollDown)
.backgroundExtensionEffect()

Resources

WWDC: 2022-10054, 2024-10147, 2025-256, 2025-323 (Build a SwiftUI app with the new design)

Docs: /swiftui/tabrole/search, /swiftui/view/tabbarminimizebehavior(_:), /swiftui/view/tabviewbottomaccessory(isenabled:content:)

Skills: axiom-swiftui-nav, axiom-swiftui-nav-diag, axiom-swiftui-26-ref, axiom-liquid-glass, axiom-swiftui-search-ref


Last Updated Based on WWDC 2022-10054, WWDC 2024-10147, WWDC 2025-256, WWDC 2025-323 (Build a SwiftUI app with the new design) Platforms iOS 16+, iPadOS 16+, macOS 13+, watchOS 9+, tvOS 16+

平台分布

Claude Code

31.74%
按下载量换算515

Codex

24.07%
按下载量换算391

OpenCode

18.01%
按下载量换算292

Antigravity

13.87%
按下载量换算225

Cursor

7.32%
按下载量换算119

Gemini CLI

3.23%
按下载量换算52

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills