如何确保视图在 SwiftUI 中遵循安全区域,而父视图在 TabView 中有效地忽略它?

How to ensure views respect Safe Area in SwiftUI while parent view ignores it efficiently in TabView?

提问人:Eddy Todd 提问时间:11/16/2023 最后编辑:HangarRashEddy Todd 更新时间:11/16/2023 访问量:19

问:

我正在开发一个用户界面类似于 TikTok 的应用程序,具有多个选项卡,包括一个全屏垂直滚动选项卡。在此滚动视图中,我希望背景延伸到安全区域之外,覆盖整个屏幕。但是,我还需要一些叠加视图才能保持在安全区域内。

目前,我正在使用此布局。当我第一次切换到第二个选项卡时,挑战就出现了。背景似乎在重建,这对性能来说并不理想,尤其是在背景是视频的情况下。GeometryReader

为了说明这一点,我创建了此问题的简化版本。它具有具有随机生成颜色的背景和代表安全区域内容的蓝色框。当滑动到下一个选项卡时背景颜色发生变化时,问题很明显,表明视图已被重建(我猜)。如何防止在切换选项卡时重新生成此视图,或者是否有针对此方案的更有效的解决方法?

import SwiftUI

struct ContentView: View {
    @State private var selectedIndex: Int = 0
    
    var body: some View {
        ZStack(alignment: .bottom) {
            TabView(selection: $selectedIndex) {
                PageView()
                Text("2nd tab")
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .edgesIgnoringSafeArea(.all)
        }
    }
}

struct PageView: View {
    @State private var paddingValue: EdgeInsets = EdgeInsets()
    
    var body: some View {
        GeometryReader { geometry in
            ScrollView {
                LazyVStack(spacing: 0){
                    ForEach(0..<10){post in
                        Rectangle()
                            .fill(randomColor())
                            .containerRelativeFrame ([.horizontal, .vertical])
                            .overlay {
                                SafeSectionView()
                                    .padding(paddingValue)
                            }
                    }
                }
                .scrollTargetLayout()
            }
            .scrollIndicators(.hidden)
            .scrollTargetBehavior(.paging)
            .ignoresSafeArea()
            .onAppear {
                if paddingValue == EdgeInsets() {
                    paddingValue = geometry.safeAreaInsets
                }
            }
        }
    }
    
    func randomColor() -> Color {
        return Color(
            red: Double.random(in: 0...1),
            green: Double.random(in: 0...1),
            blue: Double.random(in: 0...1)
        )
    }
}

struct SafeSectionView: View {
    var body: some View {
        Rectangle()
            .fill(.blue)
    }
}

#Preview {
    ContentView()
}
iOS版 SwiftUI

评论


答: 暂无答案