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

SwiftUI滚动时Section内VStack伸缩导致列表滚动卡顿

SwiftUI iOS13+ 列表滚动卡顿问题排查

问题背景

我正在开发一款集成按钮及对应操作选项的简易测试应用,为保证向后兼容性,项目最低支持版本设定为iOS 13.0。
预期实现和iOS原生应用一致的流畅滚动效果,但实际运行时列表滚动出现卡顿。我判断卡顿原因是部分VStack持续收缩、扩张,不断改变滚动内容的整体高度,进而引发滚动跳变。
问题复现视频:卡顿复现录像。当滚动到卡顿的底部位置停止滑动时,可以观察到处于收缩状态的VStack,该现象在视频末尾清晰可见。

相关代码

主视图实现代码(初始怀疑异常出现在SectionH)

import SwiftUI

struct ContentView: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
    @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
    
    var body: some View {
        if(verticalSizeClass == .regular && horizontalSizeClass == .compact) {
            VStack {
                List {
                    SectionA()
                    SectionB()
                    SectionC()
                    SectionD()
                    SectionE()
                    SectionF()
                    SectionG()
                    SectionH()
                }
                
                OtherView()
            }
        } else {
            HStack {
                List {
                    SectionA()
                    SectionB()
                    SectionC()
                    SectionD()
                    SectionE()
                    SectionF()
                    SectionG()
                    SectionH()
                }
                
                OtherView()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

普通Section示例(SectionA到SectionG实现逻辑类似,以SectionF为例)

import SwiftUI

struct SectionF: View {
    @State var bool1 : Bool = true;
    
    @State var text1: String = "text"
    @State var text2: String = "text"
    @State var text3: String = "text"
    @State var text4: String = "text"
    
    
    var body: some View {
        Section(header: Text("Section F")) {
            Button{
            } label: {
                Text("button")
            }
            
            VStack(alignment: .leading) {
                Button{
                } label: {
                    Text("button: \(bool1 ? "true" : "false")")
                }
                Toggle("bool", isOn: $bool1)
            }
            
            
            VStack(alignment: .leading) {
                Button{
                } label: {
                    Text("button")
                }
                HStack {
                    Text("text: ")
                    TextField("text", text: $text1)
                }
                HStack {
                    Text("text: ")
                    TextField("text", text: $text2)
                }
                HStack {
                    Text("text: ")
                    TextField("text", text: $text3)
                }
                HStack {
                    Text("text: ")
                    TextField("text", text: $text4)
                }
            }
            
            VStack(alignment: .leading) {
                Button{
                } label: {
                    Text("button")
                }
                HStack {
                    Text("text: ")
                    TextField("text", text: $text1)
                }
            }
        }
    }
}

struct SectionF_Previews: PreviewProvider {
    static var previews: some View {
        Form {
            SectionF()
        }
        
    }
}

初始怀疑引发问题的SectionH实现代码

import SwiftUI

struct SectionH: View {
    @State var text1: String = "text"
    @State var text2: String = "text"
    @State var picker1: String = "1"
    var picker1s = ["1", "2"]
    @State var text3: String = "text"
    @State var text4: String = "text"
    
    
    @State var bool1 : Bool = true;
    @State var text5: String = "text"
    @State var bool2 : Bool = true;
    @State var bool3 : Bool = true;
    @State var number1: String = "0"
    
    
    var body: some View {
        Section(header: Text("Section H")) {
            VStack(alignment: .leading) {
                Button{
                } label: {
                    Text("button")
                }
                
                HStack {
                    Text("text: ")
                    TextField("text", text: $text1)
                }
                
                HStack {
                    Text("text: ")
                    TextField("text", text: $text2)
                }
                VStack(alignment: .leading) {
                    Text("picker: \(picker1)")
                    Picker("picker", selection: $picker1) {
                        ForEach(picker1s, id: \.self) {
                          Text($0)
                        }
                    }.pickerStyle(.segmented)
                }
                
                HStack {
                    Text("text: ")
                    TextField("text", text: $text3)
                }
                
                HStack {
                    Text("text: ")
                    TextField("text", text: $text4)
                }
            }
        
        
            Button {
            } label: {
                Text("Button")
            }
            
            VStack(alignment: .leading) {
                Button {
                } label: {
                    Text("Button")
                }
                VStack {
                    
                    HStack {
                        Text("text: ")
                        TextField("text", text: $text1)
                    }
                    HStack {
                        Text("text: ")
                        TextField("text", text: $text2)
                    }
                    VStack(alignment: .leading) {
                        Text("picker: \(picker1)")
                        Picker("picker", selection: $picker1) {
                            ForEach(picker1s, id: \.self) {
                              Text($0)
                            }
                        }.pickerStyle(.segmented)
                    }
                }
                
                //**this is shrinking VStack!**
                VStack {
                    Toggle("bool", isOn: $bool1)
                    
                    HStack {
                        Text("text: ")
                        TextField("text", text: $text3)
                    }
                    
                    HStack {
                        Text("text: ")
                        TextField("text", text: $text5)
                    }
                    
                    Toggle("bool", isOn: $bool2)
                    
                    Toggle("bool", isOn: $bool3)
                    
                    HStack {
                        Text("number: ")
                        TextField("number", text: $number1)
                    }
                }
                
            }
        }
    }
}

struct SectionH_Previews: PreviewProvider {
    static var previews: some View {
        Form {
            SectionH()
        }
    }
}

已尝试排查方案

  • 将List替换为Form
  • 调整各个Section的排列顺序
  • 移除根据设备方向切换VStack/HStack布局的判断逻辑:该操作可以完全消除卡顿
  • 精简SectionH内的控件数量
  • 将SectionH内的选项拆分到两个独立VStack中(该修改已应用到上述给出的代码中)

问题更新

  • 移除SectionH后,卡顿问题仍未解决
  • 移除OtherView后,卡顿问题仍未解决
  • 目前推测问题和设备方向相关的状态判断逻辑存在关联

我是Swift和SwiftUI的初学者,不清楚该问题的触发原理,也未找到明确的排查解决方向,在此寻求帮助。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 12:36:20