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

SwiftUI横竖屏切换时高效追踪视图与屏幕尺寸方案

动态追踪SwiftUI视图与屏幕尺寸的可复用方案(横竖屏适配)

在SwiftUI项目中,我需要动态追踪特定视图尺寸及设备全屏尺寸,核心挑战是保证横竖屏切换时尺寸能正常更新,同时不破坏原有布局。

我基于GeometryReader与PreferenceKey实现了一套可复用方案,能动态捕获子视图和屏幕尺寸,可灵活应用到各类视图中。这里选择用ZStack的原因很明确:GeometryReader默认会占据所有可用空间,很容易打乱原有布局,而ZStack能让尺寸追踪的逻辑仅完成数据捕获,完全不干扰实际内容视图的布局。

具体实现代码

// 定义PreferenceKey用于传递尺寸数据
struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
        value = nextValue()
    }
}

// 视图修饰器:追踪自身尺寸
struct TrackSizeModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .background(
                GeometryReader { geo in
                    Color.clear
                        .preference(key: SizePreferenceKey.self, value: geo.size)
                }
            )
    }
}

// 视图修饰器:追踪屏幕全屏尺寸
struct TrackScreenSizeModifier: ViewModifier {
    func body(content: Content) -> some View {
        ZStack {
            content
            GeometryReader { screenGeo in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: screenGeo.size)
            }
            .allowsHitTesting(false) // 不拦截交互事件
        }
    }
}

// 扩展View,提供便捷调用方法
extension View {
    func trackSize(onChange: @escaping (CGSize) -> Void) -> some View {
        self
            .modifier(TrackSizeModifier())
            .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
    }
    
    func trackScreenSize(onChange: @escaping (CGSize) -> Void) -> some View {
        self
            .modifier(TrackScreenSizeModifier())
            .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
    }
}

// 使用示例
struct ContentView: View {
    @State private var viewSize: CGSize = .zero
    @State private var screenSize: CGSize = .zero
    
    var body: some View {
        VStack(spacing: 20) {
            Text("当前视图尺寸:\(viewSize.width) x \(viewSize.height)")
            Text("屏幕尺寸:\(screenSize.width) x \(screenSize.height)")
            
            RoundedRectangle(cornerRadius: 10)
                .fill(Color.blue)
                .frame(width: 200, height: 200)
                .trackSize { size in
                    viewSize = size
                }
        }
        .trackScreenSize { size in
            screenSize = size
        }
        .padding()
    }
}

希望各位开发者能针对这套方案提出改进建议,比如优化性能、简化逻辑、适配特殊场景等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:49:53