iOS16后SwiftUI程序化选中列表项及解决数组传参错误
解决iOS 16+ SwiftUI程序化导航问题
在iOS 16及以后,Apple弃用了NavigationLink(tag:selection:) API,取而代之的是NavigationStack结合NavigationPath的方式实现程序化导航。以下是修改后的代码,启动时会直接跳转到"Math"对应的详情页:
import SwiftUI import Foundation // 让BookItem遵循Hashable,才能加入NavigationPath struct BookItem: Hashable { let id: Int let name: String init(id: Int, name: String) { self.id = id self.name = name } } struct ContentView: View { let bookList: [BookItem] = [BookItem(id: 0, name: "History"), BookItem(id: 1, name: "Math"), BookItem(id: 2, name: "Science")] let selectBookItemId: Int = 1 // 管理导航路径的状态变量 @State private var path = NavigationPath() var body: some View { // 绑定path到NavigationStack NavigationStack(path: $path) { List(bookList, id: \.id) { bookItem in // 用按钮触发导航,也可替换为NavigationLink(value: bookItem) { ... } Button { path.append(bookItem) } label: { HStack { Text(bookItem.name) Spacer() } .contentShape(Rectangle()) } } // 指定BookItem类型对应的导航目标视图 .navigationDestination(for: BookItem.self) { bookItem in DetailsView(bookItem: bookItem) } // 页面加载时自动跳转到指定条目 .onAppear { if let targetBook = bookList.first(where: { $0.id == selectBookItemId }) { path.append(targetBook) } } } } } struct DetailsView: View { var bookItem: BookItem var body: some View { VStack { Text(bookItem.name) .font(.body.bold()) .foregroundColor(.blue) } } }
解决数组传参的类型不匹配错误
你遇到的Cannot convert value of type 'String' to expected argument type '[String]'错误,核心是导航目标声明的类型和实际传递的类型不匹配:你往path里添加的是[String]类型的listing,但navigationDestination声明要处理String类型,导致类型冲突。
下面是两种修正方案,推荐第一种(更符合数据逻辑):
方案一:传递完整的BookItem(推荐)
直接把整个BookItem传给详情页,便于后续扩展,不需要单独传递数组:
import SwiftUI import Foundation struct BookItem: Hashable { let id: Int let name: String let listing: [String] init(id: Int, name: String, listing: [String]) { self.id = id self.name = name self.listing = listing } } struct ContentView: View { let bookList: [BookItem] = [BookItem(id: 0, name: "History", listing: ["1", "2"]), BookItem(id: 1, name: "Math", listing: ["1", "2"]), BookItem(id: 2, name: "Science", listing: ["1", "2"])] let selectBookItemId: Int @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { List(bookList, id: \.id) { bookItem in Button { path.append(bookItem) } label: { HStack { Text(bookItem.name) Spacer() } .contentShape(Rectangle()) } } // 指定处理BookItem类型的导航 .navigationDestination(for: BookItem.self) { bookItem in DetailsView(listing: bookItem.listing) } .onAppear { if let targetBook = bookList.first(where: { $0.id == selectBookItemId }) { path.append(targetBook) } } } } } struct DetailsView: View { var listing: [String] var body: some View { VStack { // 遍历显示数组内容 ForEach(listing, id: \.self) { item in Text(item) } } } }
方案二:直接传递[String]类型
如果确实只需要传递数组,要确保navigationDestination的类型和传递的类型完全一致:
import SwiftUI import Foundation struct BookItem: Hashable { let id: Int let name: String let listing: [String] init(id: Int, name: String, listing: [String]) { self.id = id self.name = name self.listing = listing } } struct ContentView: View { let bookList: [BookItem] = [BookItem(id: 0, name: "History", listing: ["1", "2"]), BookItem(id: 1, name: "Math", listing: ["1", "2"]), BookItem(id: 2, name: "Science", listing: ["1", "2"])] let selectBookItemId: Int @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { List(bookList, id: \.id) { bookItem in Button { path.append(bookItem.listing) } label: { HStack { Text(bookItem.name) Spacer() } .contentShape(Rectangle()) } } // 修改为[String].self,匹配传递的数组类型 .navigationDestination(for: [String].self) { listing in DetailsView(bookItem: listing) } .onAppear { if let targetBook = bookList.first(where: { $0.id == selectBookItemId }) { path.append(targetBook.listing) } } } } } struct DetailsView: View { var bookItem: [String] var body: some View { VStack { ForEach(bookItem, id: \.self) { item in Text(item) } } } }
内容的提问来源于stack exchange,提问作者tech_human
相关产品推荐
相关产品推荐

