我是 SwiftUI 的新手,想從任何其他視圖導航到 SwiftUI 中的“主頁”視圖。我創建了一個主頁按鈕,該按鈕添加到多個視圖的導航欄中。主頁按鈕回傳“主頁”視圖,但導航鏈接無法正確導航并顯示錯誤資料。
我已經閱讀了其他有類似問題的人的多個答案,但這些答案至少有兩年的歷史了,從那時起 SwiftUI 發生了很大的變化。我試圖實作許多答案,但總是遇到其他問題。某些功能已被棄用,我正在尋找更具前瞻性的解決方案。
這是一些顯示問題的代碼。在此示例中,我使用 NavigationLink 中的 isActive 引數來觸發主頁按鈕,但這似乎破壞了 NavigationLink。我也嘗試過使用標簽和選擇引數并得到相同的結果。通過閱讀其他回復,我相信在“ProductFamilyView”中使用 ForEach 陳述句是參考錯誤資料的問題。但是,在這個應用程式中,我需要使用 ForEach 陳述句來顯示產品系列。
如果我嘗試呼叫 ProductFamilyView(),則沒有任何反應。在此示例中,我想導航回“ProductFamilyView”。是否有另一種方法可以在不使用 NavigationLink 的情況下導航到該視圖?
import SwiftUI
import Combine
class Navigation: ObservableObject {
@Published var productFamilyIsActive : Bool = false
}
struct ContentView: View {
@StateObject var navigation = Navigation()
var body: some View {
NavigationView {
VStack {
LoginButtonView(buttonText: "Login")
}
}
.environmentObject(navigation)
.navigationViewStyle(StackNavigationViewStyle() )
}
}
struct LoginButtonView: View {
@State private var navigated : Bool = false
var buttonText : String
var body: some View {
Button(action: {
self.navigated.toggle()
}, label: {
Text("\(buttonText)")
})
.navigationBarBackButtonHidden(true)
NavigationLink(destination: ProductFamilyView(), isActive: $navigated ) {
EmptyView()
}
}
}
struct ProductFamilyView: View { //This is my home view
private var productFamilies = ProductFamilyViewModel.loadData()
var body: some View {
List {
ForEach(productFamilies) { (product) in
ProductFamilyRow(productFamily: product.productFamily)
}
}
.navigationTitle("Product Families")
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
}
}
struct ProductFamilyRow: View {
@EnvironmentObject var navigation : Navigation
@State var productFamily : String
var body: some View {
NavigationLink(destination: PartNumberView(productFamily: productFamily), isActive: $navigation.productFamilyIsActive) {
Text("\(productFamily)")
}
.isDetailLink(false)
}
}
struct PartNumberView: View {
@State var productFamily: String
var productDetails = ProductViewModel.loadData()
var body: some View {
List {
ForEach(productDetails) { (productDetail) in
if productFamily == productDetail.productFamily {
NavigationLink(destination: PartNumberRow(productDetail: productDetail)) {
Text("\(productDetail.partNumber)")
}
}
}
}
.navigationTitle("\(productFamily)")
.navigationBarItems(trailing: HomeButtonView() )
}
}
struct PartNumberRow: View {
@State var productDetail : ProductViewModel
var body: some View {
List {
Text("Description: \(productDetail.description)")
NavigationLink(destination: ColorView(colorOptions: productDetail.colorOptions)) {
Text("Color Options")
}
}
.navigationTitle("\(productDetail.partNumber)")
.navigationBarItems(trailing: HomeButtonView() )
}
}
struct ColorView: View {
@State var colorOptions : [Item]
var body: some View {
List {
ForEach(colorOptions) { (color) in
Text("\(color.name)")
}
}
.navigationBarItems(trailing: HomeButtonView() )
}
}
struct HomeButtonView: View {
@EnvironmentObject var navigation : Navigation
var body: some View {
Button(action: {
self.navigation.productFamilyIsActive.toggle()
}, label: {
Image(systemName: "house")
})
.environmentObject(navigation)
}
}
class ProductFamilyViewModel: ObservableObject, Identifiable {
var id = UUID().uuidString
var productFamily : String = ""
init(productFamily: String) {
self.productFamily = productFamily
}
static func loadData() -> [ProductFamilyViewModel] {
let products = ["Product Family 1", "Product Family 2", "Product Family 3"]
var productFamilies : [ProductFamilyViewModel] = []
for product in products {
productFamilies.append(ProductFamilyViewModel(productFamily: product))
}
return productFamilies
}
}
struct Item: Identifiable, Codable {
var id : String {
self.name
}
var name : String
}
struct Product: Identifiable {
var id = UUID().uuidString
var partNumber : String = "part number"
var productFamily : String = "product family"
var description : String = "description"
var colorOptions : [Item] = []
}
class ProductViewModel: ObservableObject, Identifiable {
var id = UUID().uuidString
var partNumber : String
var productFamily : String
var description : String
var colorOptions : [Item]
init(model: Product) {
self.partNumber = model.partNumber
self.productFamily = model.productFamily
self.description = model.description
self.colorOptions = model.colorOptions
}
static func loadData() -> [ProductViewModel] {
let colors = [Item(name: "red"), Item(name: "white"), Item(name: "blue")]
let productDetails : [ProductViewModel] = [
ProductViewModel( model: Product(
partNumber: "100-1111-101",
productFamily: "Product Family 1",
description: "Part Number 100-1111-101",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "100-1111-102",
productFamily: "Product Family 1",
description: "Part Number 100-1111-102",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "100-1111-103",
productFamily: "Product Family 1",
description: "Part Number 100-1111-103",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "200-1111-101",
productFamily: "Product Family 2",
description: "Part Number 200-1111-101",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "200-1111-102",
productFamily: "Product Family 2",
description: "Part Number 200-1111-102",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "200-1111-103",
productFamily: "Product Family 2",
description: "Part Number 200-1111-103",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "300-1111-101",
productFamily: "Product Family 3",
description: "Part Number 300-1111-101",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "300-1111-102",
productFamily: "Product Family 3",
description: "Part Number 300-1111-102",
colorOptions: colors)
),
ProductViewModel( model: Product(
partNumber: "300-1111-103",
productFamily: "Product Family 3",
description: "Part Number 300-1111-103",
colorOptions: colors)
)
]
return productDetails
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(Navigation())
}
}
uj5u.com熱心網友回復:
首先 - 恭喜:這是第一個如此復雜的代碼,可以在復制/粘貼到 Xcode 時完美運行......并不經常發生 :)
對于您的問題:
您幾乎擁有它。唯一的問題是你productFamilyIsActive是一個布林值——它只能保存一個選定的 NavigationLink 的資訊,你有 3 個。但如果你將它更改為可選選項,它可以:
class Navigation: ObservableObject {
@Published var productFamilyIsActive : String? = nil // here
}
為此,您在 NavigationLink 上使用不同的初始化:
struct ProductFamilyRow: View {
@EnvironmentObject var navigation : Navigation
@State var productFamily : String
var body: some View {
NavigationLink(destination: PartNumberView(productFamily: productFamily),
tag: productFamily, // here
selection: $navigation.productFamilyIsActive) { // and here
Text("\(productFamily)")
}
.isDetailLink(false)
}
}
最后,您沒有設定為 false 而是設定為 nil :
struct HomeButtonView: View {
@EnvironmentObject var navigation : Navigation
var body: some View {
Button(action: {
self.navigation.productFamilyIsActive = nil // here
}, label: {
Image(systemName: "house")
})
.environmentObject(navigation)
}
}
瞧!
uj5u.com熱心網友回復:
SwiftUI 仍然UINavigationController在底層使用,anyNavigationLink將新視圖推送到堆疊上。
要回傳根視圖控制器,您需要一個popToRootViewController函式以可靠的方式展開整個導航堆疊。
在cuvenx.com上有一個非常聰明的建議是通過修改id根視圖的屬性來實作這個功能。
首先將Navigation類替換為
final class AppState : ObservableObject {
@Published var rootViewId = UUID()
}
在@main App物件中創建一個實體并將其注入環境
@main
struct MyGreatApp: App {
@StateObject var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(appState)
}
}
}
在ContentView洗掉@StateObject并將行替換.environmentObject(navigation)為
.id(appState.rootViewId)
從作為根視圖實作的后代的任何視圖導航回來
@EnvironmentObject var appState: AppState
并執行
appState.rootViewId = UUID()
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/442050.html
標籤:IOS 迅捷 swiftui-导航链接
