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

SwiftUI嵌套ScrollView导航返回后应用冻结问题求助

问题:嵌套滚动视图返回后应用冻结

环境信息:

  • SwiftUI: 5.9
  • XCode: 15.0.1
  • iPhone 11
  • iOS: 17.0.3

开发多页面应用时,Home2View通过垂直ScrollView嵌套3个水平ScrollView展示缩略图,点击缩略图可导航至CameraView。该功能首次进入页面时正常,但从CameraView点击返回按钮回到首页后,应用会冻结且无任何报错信息,无法进行操作。已知Swift滚动视图导航存在相关Bug,附上代码寻求解决方案:

struct Home2View: View {

@StateObject var accountViewModel: AccountViewModel
@StateObject var myPozeGroupViewModel: MyPozeGroupViewModel

var body: some View {
    NavigationView {
        ScrollView(.vertical) {
            VStack (spacing: 50) {
    
                ScrollView(.horizontal) {
                    horizontalList(data: myPozeGroupViewModel.top10MyPozeGroups, backgroundColor: .green)
                    }

                ScrollView(.horizontal) {
                        horizontalList(data: myPozeGroupViewModel.freshest10MyPozeGroups)
                    }
            
                ScrollView(.horizontal) {
                        horizontalList(data: myPozeGroupViewModel.letters10MyPozeGroups)
                    }
            }
        }
        .onAppear {
            
            if myPozeGroupViewModel.top10MyPozeGroups.isEmpty {
                myPozeGroupViewModel.addListenerForTop10()
            }
            
            if myPozeGroupViewModel.freshest10MyPozeGroups.isEmpty {
                myPozeGroupViewModel.addListenerForFreshest10()
            }
            
            if myPozeGroupViewModel.letters10MyPozeGroups.isEmpty {
                myPozeGroupViewModel.addListenerForLetters10()
            }
        }
    }
}

func horizontalList(data: [MyPozeGroup], backgroundColor: Color = .blue) -> some View {
    HStack(spacing:5) {
        ForEach(data) { myPozeGroup in
            NavigationLink(destination: CameraView(
                myPozeGroup: myPozeGroup,
                myPozeGroupViewModel: myPozeGroupViewModel,
                accountViewModel: accountViewModel)
            ) {
                VStack(spacing: 0) {
                    AsyncImage(url: URL(string: myPozeGroup.thumbnail ?? "")) { image in
                        image
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 150, height: 150)
                    } placeholder: {
                        ProgressView()
                    }
                    
                    Rectangle()
                        .fill(Color.white)
                        .frame(height: 20)
                        .overlay(
                            HStack {
                                Text(myPozeGroup.name ?? "")
                                    .foregroundColor(.black)
                                Spacer()
                                Text("\(myPozeGroup.counter)")
                                    .foregroundColor(.gray)
                            }
                        )
                }
                .cornerRadius(20)
            }
        }
    }
    
}

解决方案

针对iOS 17中嵌套ScrollView结合NavigationLink导致的返回冻结问题,可尝试以下几种修复方案:

1. 替换NavigationView为NavigationStack

iOS 16+官方推荐使用NavigationStack替代旧的NavigationView,后者在新版本中存在嵌套滚动视图的兼容问题。修改Home2View的根视图:

NavigationStack {
    // 原垂直ScrollView内容
}

2. 使用navigationDestination替代嵌套的NavigationLink

嵌套ScrollView中直接使用NavigationLink易引发视图层级冲突,改用navigationDestination统一管理导航目标:

  • 首先在Home2View中添加选中对象状态:
@State private var selectedPozeGroup: MyPozeGroup?
  • 在NavigationStack上添加导航目标绑定:
.navigationDestination(item: $selectedPozeGroup) { group in
    CameraView(
        myPozeGroup: group,
        myPozeGroupViewModel: myPozeGroupViewModel,
        accountViewModel: accountViewModel
    )
}
  • 修改horizontalList的点击逻辑,替换NavigationLink为TapGesture:
func horizontalList(data: [MyPozeGroup], backgroundColor: Color = .blue) -> some View {
    HStack(spacing:5) {
        ForEach(data) { myPozeGroup in
            VStack(spacing: 0) {
                AsyncImage(url: URL(string: myPozeGroup.thumbnail ?? "")) { image in
                    image
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 150, height: 150)
                } placeholder: {
                    ProgressView()
                }
                
                Rectangle()
                    .fill(Color.white)
                    .frame(height: 20)
                    .overlay(
                        HStack {
                            Text(myPozeGroup.name ?? "")
                                .foregroundColor(.black)
                            Spacer()
                            Text("\(myPozeGroup.counter)")
                                .foregroundColor(.gray)
                        }
                    )
            }
            .cornerRadius(20)
            .onTapGesture {
                selectedPozeGroup = myPozeGroup
            }
        }
    }
}

3. 给水平ScrollView设置滚动优先级

明确垂直与水平ScrollView的滚动优先级,避免交互冲突:

ScrollView(.horizontal) {
    horizontalList(data: myPozeGroupViewModel.top10MyPozeGroups, backgroundColor: .green)
}
.scrollPriority(1) // 垂直ScrollView默认优先级为0,设置更高优先级确保水平滚动响应正常

4. 优化ViewModel监听逻辑

避免返回页面后重复创建监听,在MyPozeGroupViewModel中添加初始化标记:

class MyPozeGroupViewModel: ObservableObject {
    @Published var top10MyPozeGroups: [MyPozeGroup] = []
    private var hasInitializedTop10 = false
    // 其他属性...
    
    func addListenerForTop10() {
        guard !hasInitializedTop10 else { return }
        hasInitializedTop10 = true
        // 原监听逻辑
    }
    
    // 同理处理addListenerForFreshest10和addListenerForLetters10
}

内容的提问来源于stack exchange,提问作者Gregor Sotošek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 16:15:13