Code Repo: github.com/xuchi16/vis...
Project Path: github.com/xuchi16/vis...
基本概念
苹果的各个OS生态中,有各种不同的导航栏、工具栏组件。不同组件适用的平台也不完全相同。
根据官方文档总结如下:
Definition | iOS | iPadOS | MacOS | tvOS | visionOS | watchOS | |
---|---|---|---|---|---|---|---|
Tab barTab bar doc | Tab bars use bar items to navigate between mutually exclusive panes of content in the same view. | × | Highly customizable | × | |||
Tab viewTab view doc | A tab view presents multiple mutually exclusive panes of content in the same area, which people can switch between using a tabbed control. | × | × | × | × | ||
Side barSide bar doc | A sidebar can help people navigate your app or game, providing quick access to top-level collections of content. | Consider using a tab bar instead of a sidebar | No additional considerations for tvOS | × | |||
Tool barTool bar doc | A toolbar provides convenient access to frequently used commands and controls that perform actions relevant to the current view. | Offers commonly used actions | Highly customizable | ||||
OrnamentsOrnaments doc | An ornament presents controls and information related to a window, without crowding or obscuring the window's contents. | × | × | × | × | × |
这里我们先讨论Tab bar和Side bar两种形式。
Tab bar
Tab bar会在同一区域呈现多个互斥的内容面板,用户可以通过标签控件进行切换。手机屏幕较高,因此在iOS中,b bar在屏幕底部。而在visionOS中,由于不受屏幕尺寸的限制,所以通过悬浮于窗口外的侧边栏实现。
Side bar
Side bar则更适用于宽屏幕设备,如macOS,iPadOS以及visionOS。
因此对于visionOS而言,可以同时有Tab bar和Side bar两层结构进行导航操作。
实现
Tab bar
Tab bar提供多个View的切换。实现中顶层是一个TabView<SelectionValue, Content>
。其中SelectionValue表示当前选中的View,Content表示它包含的子页面。
对于每个子页面,需要通过.tag
和.tabItem
两个modifier提供更具体的信息
.tag
为每个View提供唯一的tag.tabItem
提供图标和文案。默认展示图标,用户注视时图标会展开,显示详细的文案
这样,我们就可以获得一个Tab bar。
swift
TabView(selection: $barIdx,
content: {
Text("Tab Content 1")
.tabItem {
Label("Albums", systemImage: "rectangle.stack.fill")
}
.tag(1)
Text("Tab Content 2")
.tabItem {
Label("Memories", systemImage: "memories")
}
.tag(2)
// ...
})
数据可以通过@Environment
以注入的方式传递,并且为每个选项渲染对应的页面。
swift
struct ContentView: View {
@State var barIdx = 1
@Environment(ViewModel.self) var viewModel;
var body: some View {
@Bindable var viewModel = viewModel
TabView(selection: $barIdx, content: {
ForEach(viewModel.models) { model in
PageView(dataModel : model)
.tabItem { Label(model.labelName, systemImage: model.labelImage) }
.tag(model.id)
}
})
}
}
Side bar
Side bar顶层是NavigationSplitView
,它包含2-3列,其中第一列控制后几列的展示。每一个选项页面是一个NavigationLink
。
swift
NavigationSplitView() {
List {
NavigationLink {
Text(dataModel.description)
Text("Recent view")
} label: {
Label("Recent", systemImage: "clock")
}
NavigationLink {
Text(dataModel.description)
Text("Favorite view")
} label: {
Label("Favorite", systemImage: "suit.heart")
}
}
.navigationTitle(dataModel.labelName)
} detail: {
Text("Select an item")
}
这样我们就可以获得一个拥有2层级导航的页面。