You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:10:29