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

在ExpoView中使用HostingController的SwiftUI View无法正确裁剪边界

ExpoView中SwiftUI View顶部被裁切的解决方法

问题描述

在Expo SDK 50、iOS 16环境下,将SwiftUI View通过UIHostingController嵌入ExpoView时,出现View顶部内容被裁切的情况(附图:SwiftUI View顶部被裁切),需要让内容贴合边界正常显示。

原SwiftUI View代码

struct MySwiftUIView: View {
    var name = ""
    var options: [String] = []
    @State var isOpen = false
    @State var picker = 0
    @State var slider = 50.0
    @State var isScaled = false
    
    var body: some View {
        NavigationView {
            if #available(iOS 14.0, *) {
                ScrollView {
                    VStack(spacing: 20) {
                        Text("SwiftUI + Expo!")
                            .font(.largeTitle)
                            .scaleEffect(isScaled ? 1.5 : 1.0)
                            .foregroundColor(isScaled ? .purple : .black)
                    
                        Button("Animations work too!") {
                            withAnimation {
                                isScaled.toggle()
                            }
                        }
                    
                        NavigationLink("To Details") {
                            Text("Details")
                        }
                        Picker("Picker", selection: $picker, content: {
                            ForEach(Array(options.enumerated()), id: \.1) { index, option in
                                Text(option)
                                    .tag(index)
                            }
                        }).pickerStyle(.segmented)
                        
                        if #available(iOS 16.0, *) {
                            Button("Toggle Sheet") {
                                isOpen.toggle()
                            }.sheet(isPresented: $isOpen) {
                                Text("Sheet content")
                                    .presentationDetents([.medium, .large])
                            }.padding(.bottom, 100)
                        }
                    }
                    
                }.navigationTitle(Text("Home"))
            }
        }
    }
}

原ExpoView配置代码

class SwiftuiView: ExpoView {
    let hostingController = UIHostingController(rootView: MySwiftUIView())

    required init(appContext: AppContext? = nil) {
        super.init(appContext: appContext)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        addSubview(hostingController.view)
        NSLayoutConstraint.activate([
            hostingController.view.topAnchor.constraint(equalTo: self.topAnchor),
            hostingController.view.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            hostingController.view.leftAnchor.constraint(equalTo: self.leftAnchor),
            hostingController.view.rightAnchor.constraint(equalTo: self.rightAnchor)
        ])
    }
}

解决方法

方案1:调整SwiftUI的安全区域适配

在SwiftUI的ScrollView层级添加.edgesIgnoringSafeArea(.top),让内容忽略顶部安全区域,直接贴合边界:

修改后的SwiftUI View代码

struct MySwiftUIView: View {
    var name = ""
    var options: [String] = []
    @State var isOpen = false
    @State var picker = 0
    @State var slider = 50.0
    @State var isScaled = false
    
    var body: some View {
        NavigationView {
            if #available(iOS 14.0, *) {
                ScrollView {
                    VStack(spacing: 20) {
                        Text("SwiftUI + Expo!")
                            .font(.largeTitle)
                            .scaleEffect(isScaled ? 1.5 : 1.0)
                            .foregroundColor(isScaled ? .purple : .black)
                    
                        Button("Animations work too!") {
                            withAnimation {
                                isScaled.toggle()
                            }
                        }
                    
                        NavigationLink("To Details") {
                            Text("Details")
                        }
                        Picker("Picker", selection: $picker, content: {
                            ForEach(Array(options.enumerated()), id: \.1) { index, option in
                                Text(option)
                                    .tag(index)
                            }
                        }).pickerStyle(.segmented)
                        
                        if #available(iOS 16.0, *) {
                            Button("Toggle Sheet") {
                                isOpen.toggle()
                            }.sheet(isPresented: $isOpen) {
                                Text("Sheet content")
                                    .presentationDetents([.medium, .large])
                            }.padding(.bottom, 100)
                        }
                    }
                }
                .navigationTitle(Text("Home"))
                .edgesIgnoringSafeArea(.top) // 忽略顶部安全区域
            }
        }
    }
}

方案2:优化UIHostingController配置(可选)

在ExpoView的初始化代码中,禁用HostingController的自动滚动视图内边距调整,避免UIKit层面的额外内边距干扰:

修改后的ExpoView代码

class SwiftuiView: ExpoView {
    let hostingController = UIHostingController(rootView: MySwiftUIView())

    required init(appContext: AppContext? = nil) {
        super.init(appContext: appContext)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        hostingController.automaticallyAdjustsScrollViewInsets = false // 禁用自动内边距调整
        addSubview(hostingController.view)
        NSLayoutConstraint.activate([
            hostingController.view.topAnchor.constraint(equalTo: self.topAnchor),
            hostingController.view.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            hostingController.view.leftAnchor.constraint(equalTo: self.leftAnchor),
            hostingController.view.rightAnchor.constraint(equalTo: self.rightAnchor)
        ])
    }
}

原理说明

SwiftUI的NavigationView和ScrollView默认会为系统安全区域(如刘海、状态栏)预留内边距,当嵌入到ExpoView中时,Expo自身的布局可能已经处理了安全区域,导致双重内边距叠加,最终顶部内容被裁切。通过忽略SwiftUI的顶部安全区域适配,即可让内容贴合ExpoView的顶部边界正常显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:53:16