赞
踩
NavigationLink
是用于在具有导航能力的视图之间进行页面跳转的主要方式,包裹在 NavigationLink
中的视图都是目的地视图的预览。当用户点击这个预览时,应用会将用户导航到目的地视图。使用 NavigationLink
时,确保你在 NavigationView
中使用它,否则导航将不会发生。
最基本的 NavigationLink
用法是在 NavigationView
中直接创建一个链接到目标视图的链接。
- import SwiftUI
-
- struct ContentView: View {
- var body: some View {
- NavigationView {
- List {
- NavigationLink("Go to Detail View", destination: DetailView())
- }
- .navigationTitle("Home")
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
在动态列表中,为每个列表项创建一个 NavigationLink
。
- import SwiftUI
-
- struct ContentView: View {
- let items = ["Item 1", "Item 2", "Item 3"]
-
- var body: some View {
- NavigationView {
- List(items, id: \.self) { item in
- NavigationLink(item, destination: DetailView(item: item))
- }
- .navigationTitle("Items")
- }
- }
- }
-
- struct DetailView: View {
- let item: String
-
- var body: some View {
- Text("\(item) Detail View")
- }
- }
@State
触发导航可以使用 @State
变量和 isActive
参数来控制 NavigationLink
的激活状态。
- import SwiftUI
-
- struct ContentView: View {
- @State private var isLinkActive = false
-
- var body: some View {
- NavigationView {
- VStack {
- NavigationLink(
- destination: DetailView(),
- isActive: $isLinkActive
- ) {
- EmptyView()
- }
- Button("Tap to show details") {
- isLinkActive = true
- }
- }
- .navigationTitle("Home")
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
NavigationLink
的 LabelNavigationLink
的构造器允许你定制触发链接的 UI 部分,这就是 Label。
- import SwiftUI
-
- struct ContentView: View {
- var body: some View {
- NavigationView {
- List {
- NavigationLink(destination: DetailView()) {
- HStack {
- Image(systemName: "star.fill")
- .foregroundColor(.yellow)
- Text("Go to Detail View")
- }
- }
- }
- .navigationTitle("Home")
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
NavigationLink
在 ForEach
中在 ForEach
结构中使用 NavigationLink
可以为集合中的每个元素创建导航链接。
- import SwiftUI
-
- struct ContentView: View {
- let data = ["First", "Second", "Third"]
-
- var body: some View {
- NavigationView {
- List {
- ForEach(data, id: \.self) { item in
- NavigationLink(destination: Text("\(item) Detail View")) {
- Text(item)
- }
- }
- }
- .navigationTitle("List")
- }
- }
- }
NavigationLink
的外观你可以通过修改 NavigationLink
的 Label 部分来自定义其外观。
- import SwiftUI
-
- struct ContentView: View {
- var body: some View {
- NavigationView {
- NavigationLink(destination: DetailView()) {
- CustomCell()
- }
- }
- }
- }
-
- struct CustomCell: View {
- var body: some View {
- HStack {
- Image(systemName: "person.fill")
- VStack(alignment: .leading) {
- Text("Title")
- .font(.headline)
- Text("Subtitle")
- .font(.subheadline)
- }
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
Sheet 通常用于显示临时内容,如表单、详情或辅助选项。它不同于 NavigationLink
,后者用于在导航层次结构中推送新的视图。 Sheet 更适用于不需要保持导航历史的情况。
使用 .sheet
修饰符来展示一个模态视图,当某个布尔值为 true
时显示。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingSheet = false
-
- var body: some View {
- Button("Show Sheet") {
- showingSheet.toggle()
- }
- .sheet(isPresented: $showingSheet) {
- SheetView()
- }
- }
- }
-
- struct SheetView: View {
- var body: some View {
- Text("Sheet View")
- }
- }
onDismiss
处理 Sheet 关闭可以提供一个 onDismiss
的闭包来处理 Sheet 被关闭时的事件。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingSheet = false
-
- var body: some View {
- Button("Show Sheet") {
- showingSheet.toggle()
- }
- .sheet(isPresented: $showingSheet, onDismiss: {
- print("Sheet was dismissed.")
- }) {
- SheetView()
- }
- }
- }
-
- struct SheetView: View {
- var body: some View {
- Text("Sheet View")
- }
- }
item
展示 Sheet当你需要根据某个可选的数据项展示 Sheet 时,可以使用 item
参数。
- import SwiftUI
-
- struct ContentView: View {
- @State private var selectedItem: String?
-
- var body: some View {
- Button("Show Sheet with Item") {
- selectedItem = "Detail"
- }
- .sheet(item: $selectedItem) { item in
- DetailView(item: item)
- }
- }
- }
-
- struct DetailView: View {
- let item: String
-
- var body: some View {
- Text("\(item) View")
- }
- }
sheet
结合列表在列表中为每个条目展示不同的 Sheet。
- import SwiftUI
-
- struct ContentView: View {
- let items = ["Item 1", "Item 2", "Item 3"]
- @State private var selectedItem: String?
-
- var body: some View {
- NavigationView {
- List {
- ForEach(items, id: \.self) { item in
- Button(action: {
- selectedItem = item
- }) {
- Text(item)
- }
- }
- }
- .sheet(item: $selectedItem) { item in
- DetailView(item: item)
- }
- }
- }
- }
-
- struct DetailView: View {
- let item: String
-
- var body: some View {
- Text("\(item) Detail View")
- }
- }
sheet
结合自定义触发器你可以创建一个自定义的触发器,例如一个自定义的视图,当点击时,展示 Sheet。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingSheet = false
-
- var body: some View {
- CustomButton(showingSheet: $showingSheet)
- .sheet(isPresented: $showingSheet) {
- SheetView()
- }
- }
- }
-
- struct CustomButton: View {
- @Binding var showingSheet: Bool
-
- var body: some View {
- Button(action: {
- showingSheet = true
- }) {
- Text("Show Custom Sheet")
- }
- }
- }
-
- struct SheetView: View {
- var body: some View {
- Text("Custom Sheet View")
- }
- }
fullScreenCover
是用来覆盖全屏显示内容的,类似于 sheet
,但是它会占据整个屏幕。
fullScreenCover
使用使用 .fullScreenCover
修饰符来展示一个全屏覆盖视图,它会在某个布尔值为 true
时显示。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingFullScreenCover = false
-
- var body: some View {
- Button("Show Full Screen Cover") {
- showingFullScreenCover.toggle()
- }
- .fullScreenCover(isPresented: $showingFullScreenCover) {
- FullScreenCoverView()
- }
- }
- }
-
- struct FullScreenCoverView: View {
- var body: some View {
- Text("Full Screen Cover View")
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .background(Color.blue)
- }
- }
onDismiss
处理全屏覆盖关闭可以提供一个 onDismiss
的闭包来处理全屏覆盖被关闭时的事件。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingFullScreenCover = false
-
- var body: some View {
- Button("Show Full Screen Cover") {
- showingFullScreenCover.toggle()
- }
- .fullScreenCover(isPresented: $showingFullScreenCover, onDismiss: {
- print("Full Screen Cover was dismissed.")
- }) {
- FullScreenCoverView()
- }
- }
- }
-
- struct FullScreenCoverView: View {
- var body: some View {
- Text("Full Screen Cover View")
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .background(Color.green)
- }
- }
fullScreenCover
和 item
当你需要根据某个可选的数据项展示全屏覆盖时,可以使用 item
参数。
- import SwiftUI
-
- struct ContentView: View {
- @State private var selectedItem: String?
-
- var body: some View {
- Button("Show Full Screen Cover with Item") {
- selectedItem = "Detail"
- }
- .fullScreenCover(item: $selectedItem) { item in
- FullScreenDetailView(item: item)
- }
- }
- }
-
- struct FullScreenDetailView: View {
- let item: String
-
- var body: some View {
- VStack {
- Text("\(item) Full Screen Detail View")
- Button("Dismiss") {
- // Normally you would use an environment variable to dismiss
- }
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .background(Color.red)
- }
- }
fullScreenCover
结合环境变量你可以使用环境变量 presentationMode
来关闭全屏覆盖。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingFullScreenCover = false
-
- var body: some View {
- Button("Show Full Screen Cover") {
- showingFullScreenCover.toggle()
- }
- .fullScreenCover(isPresented: $showingFullScreenCover) {
- FullScreenCoverViewWithDismiss()
- }
- }
- }
-
- struct FullScreenCoverViewWithDismiss: View {
- @Environment(\.presentationMode) var presentationMode
-
- var body: some View {
- Button("Tap to dismiss") {
- presentationMode.wrappedValue.dismiss()
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .background(Color.purple)
- }
- }
fullScreenCover
的按钮可以创建一个自定义的按钮视图,当点击时,展示全屏覆盖。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingFullScreenCover = false
-
- var body: some View {
- CustomFullScreenCoverButton(showingFullScreenCover: $showingFullScreenCover)
- .fullScreenCover(isPresented: $showingFullScreenCover) {
- FullScreenCoverViewWithDismiss()
- }
- }
- }
-
- struct CustomFullScreenCoverButton: View {
- @Binding var showingFullScreenCover: Bool
-
- var body: some View {
- Button(action: {
- showingFullScreenCover = true
- }) {
- Text("Show Custom Full Screen Cover")
- }
- }
- }
-
- struct FullScreenCoverViewWithDismiss: View {
- @Environment(\.presentationMode) var presentationMode
-
- var body: some View {
- Button("Tap to dismiss") {
- presentationMode.wrappedValue.dismiss()
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .background(Color.orange)
- }
- }
程序化导航(Programmatic Navigation)指的是通过代码控制页面跳转,而不是使用用户界面元素(如按钮)的默认行为。这种方式在某些情况下非常有用,比如在后台任务完成后自动跳转页面,或者基于复杂的逻辑条件来导航。
要在 SwiftUI 中实现程序化导航,通常会用到 NavigationLink
结合一个绑定的布尔值,或者使用 NavigationLink
的 isActive
参数。
NavigationLink
和布尔值下面这个例子中,NavigationLink
被隐藏了,因为我们不需要显示它的视图。当 navigate
变为 true
时,会触发导航到 DetailView
。
- import SwiftUI
-
- struct ContentView: View {
- @State private var navigate = false
-
- var body: some View {
- NavigationView {
- VStack {
- Button("Navigate") {
- navigate = true
- }
- // 隐藏的 NavigationLink
- NavigationLink(destination: DetailView(), isActive: $navigate) {
- EmptyView()
- }
- }
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
NavigationLink
的 tag
和 selection
参数如果有多个导航目标,你可以使用 tag
和 selection
来区分不同的导航路径。
- import SwiftUI
-
- struct ContentView: View {
- @State private var selection: String?
-
- var body: some View {
- NavigationView {
- VStack {
- Button("Navigate to Detail 1") {
- selection = "Detail1"
- }
- Button("Navigate to Detail 2") {
- selection = "Detail2"
- }
- NavigationLink(destination: DetailView1(), tag: "Detail1", selection: $selection) { EmptyView() }
- NavigationLink(destination: DetailView2(), tag: "Detail2", selection: $selection) { EmptyView() }
- }
- }
- }
- }
-
- struct DetailView1: View {
- var body: some View {
- Text("Detail View 1")
- }
- }
-
- struct DetailView2: View {
- var body: some View {
- Text("Detail View 2")
- }
- }
.onAppear
触发程序化导航有时候,你可能希望在视图出现时自动触发导航,比如根据某个状态或者数据加载完成后。
- import SwiftUI
-
- struct ContentView: View {
- @State private var autoNavigate = false
-
- var body: some View {
- NavigationView {
- VStack {
- NavigationLink(destination: DetailView(), isActive: $autoNavigate) {
- EmptyView()
- }
- .isDetailLink(false)
- .onAppear {
- // 假设这里有一些逻辑判断或者异步操作完成后
- DispatchQueue.main.asyncAfter(deadline: .now() + 2) { // 延迟2秒
- autoNavigate = true
- }
- }
- }
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
NavigationLink
无界面跳转有时候,你可能希望隐藏 NavigationLink
,让导航完全由代码控制。你可以将 NavigationLink
放在 EmptyView
中,然后使用状态变量控制导航。
- import SwiftUI
-
- struct ContentView: View {
- @State private var isLinkActive = false
-
- var body: some View {
- NavigationView {
- VStack {
- Button("Navigate Programmatically") {
- isLinkActive = true
- }
-
- // 隐藏的 NavigationLink
- NavigationLink("", destination: DetailView(), isActive: $isLinkActive)
- }
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
NavigationPath
和 NavigationStack
在最新版本的 SwiftUI 中,NavigationPath
和 NavigationStack
提供了更灵活的导航方式。你可以通过直接操作路径来进行导航。
下面这个例子中,点击按钮将 DetailView
添加到 navigationPath
中,这将触发导航到 DetailView
。
- import SwiftUI
-
- struct ContentView: View {
- @State private var navigationPath = NavigationPath()
-
- var body: some View {
- NavigationStack(path: $navigationPath) {
- Button("Navigate Programmatically") {
- navigationPath.append(DetailView())
- }
- .navigationDestination(for: DetailView.self) { detailView in
- detailView
- }
- }
- }
- }
-
- struct DetailView: View {
- var body: some View {
- Text("Detail View")
- }
- }
TabView
可以用来创建一个包含多个子视图的标签页界面,每个子视图都与一个标签关联。用户可以通过点击不同的标签来切换不同的视图。
在最基本的情况下,TabView
中的每个标签和视图是静态定义的,通过直接嵌套视图来创建。
- import SwiftUI
-
- struct ContentView: View {
- var body: some View {
- TabView {
- Text("首页")
- .tabItem {
- Image(systemName: "house.fill")
- Text("首页")
- }
-
- Text("设置")
- .tabItem {
- Image(systemName: "gear")
- Text("设置")
- }
- }
- }
- }
TabView
也可以根据数据动态生成标签页。使用 ForEach
结构来循环创建多个标签。
- import SwiftUI
-
- struct ContentView: View {
- private var tabs = ["首页", "设置", "个人"]
-
- var body: some View {
- TabView {
- ForEach(tabs, id: \.self) { tab in
- Text(tab)
- .tabItem {
- Image(systemName: "\(tab).fill")
- Text(tab)
- }
- }
- }
- }
- }
@State
控制当前选中的标签你可以通过绑定一个 @State
变量到 TabView
的 selection
参数来控制当前选中的标签。
下面例子中,使用 .tag
标记每个视图,selectedTab
变量的值与标签的标记相对应,通过改变 selectedTab
的值来改变当前选中的标签。
- import SwiftUI
-
- struct ContentView: View {
- @State private var selectedTab = "首页"
-
- var body: some View {
- TabView(selection: $selectedTab) {
- Text("首页")
- .tabItem {
- Image(systemName: "house.fill")
- Text("首页")
- }
- .tag("首页") // 每个页面需要一个唯一的 tag
-
- Text("设置")
- .tabItem {
- Image(systemName: "gear")
- Text("设置")
- }
- .tag("设置") // 每个页面需要一个唯一的 tag
- }
- }
- }
在某些情况下,你可能希望能够编程方式切换当前的标签页,比如响应某个事件。你可以通过修改绑定到 TabView
的 selection
属性的变量来实现。
- import SwiftUI
-
- struct ContentView: View {
- @State private var selectedTab = "首页"
-
- var body: some View {
- VStack {
- Button("切换到设置") {
- selectedTab = "设置"
- }
-
- TabView(selection: $selectedTab) {
- Text("首页")
- .tabItem {
- Image(systemName: "house.fill")
- Text("首页")
- }
- .tag("首页")
-
- Text("设置")
- .tabItem {
- Image(systemName: "gear")
- Text("设置")
- }
- .tag("设置")
- }
- }
- }
- }
自定义 TabView
的样式,比如修改标签栏的背景色、字体颜色等。
通过直接访问 UITabBar
的 appearance
方法来改变标签栏的背景色。这种方法适用于更改全局的样式,但需要注意这种更改影响到整个 app 的 TabView
样式。
- import SwiftUI
-
- struct ContentView: View {
- init() {
- // 自定义 TabBar 的样式
- UITabBar.appearance().backgroundColor = UIColor.systemGray6
- }
-
- var body: some View {
- TabView {
- Text("首页")
- .tabItem {
- Image(systemName: "house.fill")
- Text("首页")
- }
-
- Text("设置")
- .tabItem {
- Image(systemName: "gear")
- Text("设置")
- }
- }
- // 更多自定义样式可以在这里设置
- }
- }
Popover
是一种弹出视图,当用户与某个视图交互时,它可以从该视图或按钮弹出提供额外信息或选项。Popover
在 iPad 上以弹出框的形式显示,在 iPhone 上则通常全屏显示。
要在 SwiftUI 中使用 Popover
,你需要绑定一个布尔值来控制 Popover
的显示和隐藏。
这里展示一个简单的 Popover
示例,当点击一个按钮时,它会显示一个弹出视图。
- import SwiftUI
-
- struct ContentView: View {
- // 用于控制 Popover 是否显示
- @State private var showingPopover = false
-
- var body: some View {
- Button("显示 Popover") {
- self.showingPopover = true
- }
- .popover(isPresented: $showingPopover) {
- // 这里是 Popover 的内容
- Text("这是一个 Popover")
- .font(.headline)
- .padding()
- }
- }
- }
你可以定义一个自定义视图,并在 Popover
中显示它。
- import SwiftUI
-
- struct PopoverContentView: View {
- var body: some View {
- VStack {
- Text("这是自定义内容")
- Button("关闭") {
- // 这里需要一个方法来关闭 Popover
- }
- }
- .padding()
- }
- }
-
- struct ContentView: View {
- @State private var showingPopover = false
-
- var body: some View {
- Button("显示 Popover") {
- self.showingPopover = true
- }
- .popover(isPresented: $showingPopover) {
- PopoverContentView()
- }
- }
- }
在某些情况下,你可能想在 Popover 中放置一个导航链接,允许用户导航到另一个视图。
- import SwiftUI
-
- struct DetailView: View {
- var body: some View {
- Text("详细视图内容")
- }
- }
-
- struct ContentView: View {
- @State private var showingPopover = false
-
- var body: some View {
- NavigationView {
- Button("点击显示 Popover") {
- self.showingPopover.toggle()
- }
- .popover(isPresented: $showingPopover) {
- NavigationLink(destination: DetailView()) {
- Text("前往详细视图")
- }
- .padding()
- }
- }
- }
- }
通常,你可能希望在 Popover
内部提供一个关闭按钮,下面的示例展示了如何实现:
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingPopover = false
-
- var body: some View {
- Button("显示 Popover") {
- self.showingPopover = true
- }
- .popover(isPresented: $showingPopover) {
- VStack {
- Text("带关闭按钮的 Popover")
- Button("关闭") {
- self.showingPopover = false
- }
- .padding()
- }
- }
- }
- }
sheet
和 popover
进行适配在 iPad 和 iPhone 设备上,你可能想要根据不同的屏幕大小来适配 Popover
或 Sheet
的显示。可以使用 .popover
和 .sheet
的组合来实现。
针对不同的设备和屏幕尺寸适配 Popover
和 Sheet
的展示方式,我们通常需要依据环境变量 horizontalSizeClass
来决定使用哪一种。为了简化示例,我将提供一个针对 horizontalSizeClass
进行条件判断的代码示例,在 .regular
大小类时使用 Popover
,而在 .compact
大小类时使用 Sheet
。
- import SwiftUI
-
- struct DetailView: View {
- var body: some View {
- Text("详细视图内容")
- .font(.title)
- }
- }
-
- struct ContentView: View {
- @State private var showDetails = false
- @Environment(\.horizontalSizeClass) var sizeClass
-
- var body: some View {
- Button("显示详情") {
- self.showDetails = true
- }
- .sheet(isPresented: $showDetails, onDismiss: {
- self.showDetails = false
- }) {
- // 在 compact size class 下显示 Sheet
- if sizeClass == .compact {
- DetailView()
- }
- }
- .popover(isPresented: $showDetails) {
- // 在 regular size class 下显示 Popover
- if sizeClass == .regular {
- DetailView()
- }
- }
- }
- }
有时你可能需要根据特定条件来显示 Popover。你可以在 .popover
修饰符中使用条件语句来实现这一点。
- import SwiftUI
-
- struct ContentView: View {
- @State private var showingPopover = false
- @State private var condition = false
-
- var body: some View {
- Button("点击显示 Popover") {
- condition = true
- self.showingPopover.toggle()
- }
- .popover(isPresented: $showingPopover) {
- if condition {
- Text("条件为真时显示的视图")
- } else {
- Text("条件为假时显示的视图")
- }
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。