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

SwiftUI中LazyYStack嵌套XStack为何会重建内容?

SwiftUI LazyVStack嵌套容器视图导致子视图重建的原因分析

问题场景与现象

给定以下视图结构:

struct ContentView: View {
  var body: some View {
    ScrollView(.vertical) {
      LazyVStack {
        ForEach((0...40), id: \.self) { index in
          MyView()  // (1)
          VStack {
            MyView()  // (2)
          }
        }
      }
    }
  }
}

struct MyView: View {
    var body: some View {
        Color.random
        // 添加打印后会输出:MyView: @self changed
        // let _ = Self._printChanges()
    }
}

现象:向下滚动使MyView (2)移出屏幕,再向上滚动返回时,MyView (2)的颜色会随机变化,而MyView (1)的颜色保持不变。通过_printChanges()可以看到MyView (2)触发了@self changed的重建通知。

核心原因分析

这是SwiftUI视图身份识别与Lazy容器复用逻辑共同作用的结果:

  • 直接子视图(MyView 1)的稳定逻辑:MyView (1)是ForEach的直接子视图,LazyVStack会借助ForEach提供的id(这里是index)来跟踪视图的身份。当视图滚出屏幕被回收,再次滚入时,SwiftUI会通过id判定这是同一个视图实例,再加上MyView是无状态的空结构体,等价性判断为相同,因此不会重新计算body,颜色保持不变。
  • 嵌套容器内视图(MyView 2)的重建逻辑:嵌套的VStack(或其他容器)作为ForEach的子视图,本身没有显式的身份标识(未添加.id()修饰器)。当LazyVStack回收该容器后再次重建时,SwiftUI无法识别这是同一个容器实例,会创建全新的VStack结构体。容器的body重建时,其内部的MyView (2)会被重新初始化,SwiftUI会判定该视图的上下文发生变化(即@self changed),因此重新计算body,导致Color.random重新生成,颜色改变。

解决方案

给嵌套的容器视图添加显式的身份标识,让SwiftUI能跟踪其身份:

ForEach((0...40), id: \.self) { index in
  MyView()  // (1)
  VStack {
    MyView()  // (2)
  }
  .id(index) // 添加身份标识
}

添加.id(index)后,LazyVStack会通过id识别嵌套容器的身份,滚回时不会创建新的容器实例,内部的MyView (2)也不会触发不必要的body重建,颜色会保持稳定。

内容的提问来源于stack exchange,提问作者Daniel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:10:14