SwiftUI中修改Binding属性导致页面自动返回的问题求助
问题:修改Binding值后导航页面自动返回的原因与解决办法
将PctView推入NavigationView导航栈后,在PctView中修改Binding绑定的completionPct数值时,页面会自动关闭返回,相关代码如下:
import SwiftUI struct Technology: Identifiable { var id: UUID = UUID() var techName: String var completionPct: Float = 0.0 } struct parentView: View { @State var technology = Technology(techName: "Front End") @State var tempList = [1,2] var body: some View { NavigationView { VStack { NavigationLink { ChildView(technology: $technology) } label: { Text(technology.techName) } }.navigationTitle(technology.techName) } } } struct ChildView: View { @Binding var technology: Technology var body: some View { VStack { Text(technology.techName) NavigationLink { PctView(completionPct: $technology.completionPct) } label: { Text("Go To Pct Changing View") }.navigationTitle(technology.techName) } } } struct PctView: View { @Binding var completionPct: Float var body: some View { Button("Change Pct") { completionPct = completionPct + 0.1 }.navigationTitle("Pct View") } } struct Test: PreviewProvider { static var previews: some View { parentView() } }
原因分析
核心问题在于Technology是值类型(结构体)。值类型的特性是:修改其内部属性时,会生成一个全新的实例替换原实例。而parentView中的NavigationLink直接依赖这个technology实例,当实例被替换后,SwiftUI会判定导航链路的数据源发生了根本性变化,从而重新渲染整个导航结构,导致当前的PctView被弹出,自动返回上一级页面。
解决思路
方案1:将结构体改为引用类型(类)
把Technology从结构体改成类,这样修改内部属性时不会生成新实例,只是修改现有实例的属性,SwiftUI不会触发导航链路的重建。
修改后的代码:
import SwiftUI class Technology: Identifiable { var id: UUID = UUID() var techName: String var completionPct: Float = 0.0 init(techName: String) { self.techName = techName } } struct parentView: View { @StateObject var technology = Technology(techName: "Front End") @State var tempList = [1,2] var body: some View { NavigationView { VStack { NavigationLink { ChildView(technology: technology) } label: { Text(technology.techName) } }.navigationTitle(technology.techName) } } } struct ChildView: View { @ObservedObject var technology: Technology var body: some View { VStack { Text(technology.techName) NavigationLink { PctView(completionPct: $technology.completionPct) } label: { Text("Go To Pct Changing View") }.navigationTitle(technology.techName) } } } struct PctView: View { @Binding var completionPct: Float var body: some View { Button("Change Pct") { completionPct = completionPct + 0.1 }.navigationTitle("Pct View") } } struct Test: PreviewProvider { static var previews: some View { parentView() } }
修改要点:
- 将
Technology改为类并添加初始化方法 parentView用@StateObject管理类实例,确保生命周期正确ChildView用@ObservedObject接收类实例,监听属性变化
方案2:单独抽离绑定属性(保留结构体)
如果坚持使用结构体,可以把completionPct单独作为@State变量抽离出来,避免修改整个结构体实例,示例如下:
struct parentView: View { @State var techName = "Front End" @State var completionPct: Float = 0.0 @State var tempList = [1,2] var body: some View { NavigationView { VStack { NavigationLink { ChildView(techName: techName, completionPct: $completionPct) } label: { Text(techName) } }.navigationTitle(techName) } } } struct ChildView: View { let techName: String @Binding var completionPct: Float var body: some View { VStack { Text(techName) NavigationLink { PctView(completionPct: $completionPct) } label: { Text("Go To Pct Changing View") }.navigationTitle(techName) } } }
这样修改completionPct时,只会更新单个变量,不会触发整个结构体的替换,导航页面也就不会自动返回了。
内容的提问来源于stack exchange,提问作者Aaban Tariq Murtaza
相关产品推荐
相关产品推荐

