NavigationSplitView侧边栏切换列表后推送动画失效问题咨询
在NavigationSplitView中实现了通过工具栏Picker切换两类列表的侧边栏,切换数据后首次选择列表项时,iPhone上无法显示推送动画,但iPad端运行正常。
以下是原代码:
import SwiftUI struct ContentView: View { @State private var tab: PickerTab = .fruits @State private var selectedFruit: Fruit? @State private var selectedVegetable: Vegetable? private var fruits: [Fruit] = [ Fruit(name: "Strawberry", color: .red), Fruit(name: "Blueberry", color: .blue) ] private var vegetables: [Vegetable] = [ Vegetable(name: "Carrot", color: .orange), Vegetable(name: "Broccoli", color: .green) ] var body: some View { NavigationSplitView { Group { switch tab { case .fruits: List(fruits, selection: $selectedFruit) { fruit in NavigationLink(value: fruit) { Text(fruit.name) } } case .vegetables: List(vegetables, selection: $selectedVegetable) { vegetable in NavigationLink(value: vegetable) { Text(vegetable.name) } } } } .toolbar { ToolbarItem(placement: .principal) { Picker("Sidebar", selection: $tab) { ForEach(PickerTab.allCases, id: \.self) { tab in Text(tab.rawValue.capitalized) } } .pickerStyle(.segmented) } } } detail: { switch tab { case .fruits: if let selectedFruit { Text(selectedFruit.name) .foregroundStyle(selectedFruit.color) } case .vegetables: if let selectedVegetable { Text(selectedVegetable.name) .foregroundStyle(selectedVegetable.color) } } } } } enum PickerTab: String, Hashable, CaseIterable { case fruits case vegetables } struct Fruit: Hashable, Identifiable { let id = UUID() let name: String let color: Color } struct Vegetable: Hashable, Identifiable { let id = UUID() let name: String let color: Color }
问题原因
切换Picker时,未重置另一类列表的选中状态变量(如切换到水果列表时,蔬菜的selectedVegetable仍保留之前的值),导致NavigationSplitView在iPhone折叠模式下无法正确识别状态变化,从而跳过推送动画。
解决方案
方案1:切换tab时重置未激活类别的选中状态
添加onChange监听tab切换事件,将未使用的选中状态置为nil,确保状态同步:
import SwiftUI struct ContentView: View { @State private var tab: PickerTab = .fruits @State private var selectedFruit: Fruit? @State private var selectedVegetable: Vegetable? private var fruits: [Fruit] = [ Fruit(name: "Strawberry", color: .red), Fruit(name: "Blueberry", color: .blue) ] private var vegetables: [Vegetable] = [ Vegetable(name: "Carrot", color: .orange), Vegetable(name: "Broccoli", color: .green) ] var body: some View { NavigationSplitView { Group { switch tab { case .fruits: List(fruits, selection: $selectedFruit) { fruit in NavigationLink(value: fruit) { Text(fruit.name) } } case .vegetables: List(vegetables, selection: $selectedVegetable) { vegetable in NavigationLink(value: vegetable) { Text(vegetable.name) } } } } .toolbar { ToolbarItem(placement: .principal) { Picker("Sidebar", selection: $tab) { ForEach(PickerTab.allCases, id: \.self) { tab in Text(tab.rawValue.capitalized) } } .pickerStyle(.segmented) } } // 关键:切换tab时重置另一类选中状态 .onChange(of: tab) { newTab in if newTab == .fruits { selectedVegetable = nil } else { selectedFruit = nil } } } detail: { switch tab { case .fruits: if let selectedFruit { Text(selectedFruit.name) .foregroundStyle(selectedFruit.color) } else { Text("Select a fruit") } case .vegetables: if let selectedVegetable { Text(selectedVegetable.name) .foregroundStyle(selectedVegetable.color) } else { Text("Select a vegetable") } } } } } // 枚举和模型定义保持不变 enum PickerTab: String, Hashable, CaseIterable { case fruits case vegetables } struct Fruit: Hashable, Identifiable { let id = UUID() let name: String let color: Color } struct Vegetable: Hashable, Identifiable { let id = UUID() let name: String let color: Color }
方案2:统一管理选中状态变量
用一个AnyHashable类型的变量存储选中项,避免维护多个状态变量,状态同步更简洁:
import SwiftUI struct ContentView: View { @State private var tab: PickerTab = .fruits @State private var selectedItem: AnyHashable? // 统一管理选中项 private var fruits: [Fruit] = [ Fruit(name: "Strawberry", color: .red), Fruit(name: "Blueberry", color: .blue) ] private var vegetables: [Vegetable] = [ Vegetable(name: "Carrot", color: .orange), Vegetable(name: "Broccoli", color: .green) ] var body: some View { NavigationSplitView { Group { switch tab { case .fruits: List(fruits, selection: $selectedItem) { fruit in NavigationLink(value: fruit) { Text(fruit.name) } } case .vegetables: List(vegetables, selection: $selectedItem) { vegetable in NavigationLink(value: vegetable) { Text(vegetable.name) } } } } .toolbar { ToolbarItem(placement: .principal) { Picker("Sidebar", selection: $tab) { ForEach(PickerTab.allCases, id: \.self) { tab in Text(tab.rawValue.capitalized) } } .pickerStyle(.segmented) } } } detail: { switch tab { case .fruits: if let fruit = selectedItem as? Fruit { Text(fruit.name) .foregroundStyle(fruit.color) } else { Text("Select a fruit") } case .vegetables: if let vegetable = selectedItem as? Vegetable { Text(vegetable.name) .foregroundStyle(vegetable.color) } else { Text("Select a vegetable") } } } } } // 枚举和模型定义保持不变 enum PickerTab: String, Hashable, CaseIterable { case fruits case vegetables } struct Fruit: Hashable, Identifiable { let id = UUID() let name: String let color: Color } struct Vegetable: Hashable, Identifiable { let id = UUID() let name: String let color: Color }
两种方案都能解决iPhone上的动画问题,方案2更简洁,减少状态维护成本。
内容的提问来源于stack exchange,提问作者rizz
相关产品推荐
相关产品推荐

