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

SwiftUI横竖屏切换LazyVGrid列数时如何避免fullScreenIsPresented自动消失

问题根因

当设备旋转触发sizeClass变化时,你直接在ScrollView内容块内生成GridItem数组,会导致LazyVGrid的布局配置每次重绘都生成新的实例,SwiftUI会将其判定为全新的视图,既会丢失原有滚动位置的上下文,也会因为父视图层级的强制重绘,导致子视图弹出的全屏模态被意外销毁。

修复方案
  • 把GridItem布局配置挪到计算属性中,避免不必要的实例刷新
  • 给LazyVGrid添加固定的唯一标识,告知SwiftUI重绘时复用原有视图状态
  • 绑定滚动位置,横竖屏切换时系统会自动适配新的布局尺寸恢复滚动偏移
  • 全屏弹出的状态fullScreenIsPresented要声明在Feed_View层级,不要放在FeedCell等子视图中,避免子视图重制导致状态丢失
修正后代码示例
struct Feed_View: View {
    @EnvironmentObject var viewModel : Post_View_Model 
    @Environment(\.verticalSizeClass) var sizeClass 
    @FocusState private var isFocused: Bool
    // iOS17+ 滚动位置绑定,低版本可以用ScrollViewReader实现
    @State private var scrollPosition = ScrollPosition()
    // 全屏弹窗状态移到当前层声明
    @State private var fullScreenIsPresented = false
    @State private var selectedPost: PostModel? // 可选,用来传选中的单元格数据

    // 布局改成计算属性,不要在body的视图构建逻辑里生成数组
    private var layout: [GridItem] {
        Array(repeating: GridItem(.flexible(), spacing: 10), count: sizeClass == .compact ? 3 : 2)
    }

    var body: some View {
        Color("BGColor").ignoresSafeArea() 
        ZStack {
            VStack (alignment: .center, spacing: 0) {
                NavBar_View()
                    .frame(maxHeight: 40, alignment: .center)
                // 绑定滚动位置
                ScrollView (.vertical, showsIndicators: false) {
                    LazyVGrid(columns: layout, spacing: 10) {
                        ForEach (viewModel.posts, id: \.self) { post in
                            Feed_Cell(postModel: post)
                                .onTapGesture {
                                    selectedPost = post
                                    fullScreenIsPresented = true
                                }
                        }
                    }
                    .padding(.horizontal, 10).padding(.vertical, 10)
                    // 给LazyVGrid加固定id,避免布局变化被判定为新视图
                    .id("FeedFixedLazyVGrid")
                }
                .scrollPosition($scrollPosition)
            }
        }
        // 全屏弹窗写在最外层,不受内部滚动视图重绘影响
        .fullScreenCover(isPresented: $fullScreenIsPresented) {
            if let post = selectedPost {
                // 你的全屏页实现
                PostFullScreenView(post: post)
            }
        }
    }
}

如果是iOS16及更低版本,不需要ScrollPosition的相关代码,只保留给LazyVGrid加固定id、布局挪到计算属性、全屏弹窗移到外层三个修改即可修复。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 07:15:09