iOS17中Sheet内嵌套TextField导致presentationDetent失效问题
iOS17中带TextField的PageTabViewStyle TabView导致Sheet的presentationDetent失效
问题描述
在iOS16中,设置了.medium或自定义尺寸presentationDetent的Sheet里,嵌入使用PageTabViewStyle的TabView可以正常展示类UIPageView内容(仅存在安全区忽略问题)。但升级到iOS17后,只要TabView内嵌套任意层级的TextField,Sheet就会强制全屏显示,同时出现布局错乱问题;将TextField替换为其他视图(如Color.green)则恢复正常。
复现代码
import SwiftUI struct ContentView: View { @State var text = "text" @State var showSheet = false var body: some View { VStack { Button("SHOW SHEET") { showSheet = true } } .sheet(isPresented: $showSheet) { TabView { TextField("Venue name", text: $text, axis: .vertical) TextField("Venue name", text: $text, axis: .vertical) } .tabViewStyle(PageTabViewStyle()) .presentationDetents([.medium]) } } }
测试环境
- Xcode 15.0 构建
- iOS17 模拟器/真机可复现
- iOS16 模拟器/真机运行正常
可行解决方案
目前有两种临时 workaround 可以解决该问题:
1. 给TabView添加明确的高度约束
通过限制TabView的高度,让Sheet能正确识别内容尺寸,避免被TextField的布局需求强制拉伸全屏:
.sheet(isPresented: $showSheet) { TabView { TextField("Venue name", text: $text, axis: .vertical) TextField("Venue name", text: $text, axis: .vertical) } .tabViewStyle(PageTabViewStyle()) .frame(height: UIScreen.main.bounds.height * 0.5) // 匹配.medium的大致高度 .presentationDetents([.medium]) }
2. 使用UIKit的UIPageViewController替代SwiftUI TabView
由于这是iOS17 SwiftUI的底层交互bug,用UIKit组件包装可以规避问题:
struct PageViewController: UIViewControllerRepresentable { var controllers: [UIViewController] func makeUIViewController(context: Context) -> UIPageViewController { let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal) pageVC.dataSource = context.coordinator pageVC.setViewControllers([controllers[0]], direction: .forward, animated: false) return pageVC } func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UIPageViewControllerDataSource { var parent: PageViewController init(_ parent: PageViewController) { self.parent = parent } func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let index = parent.controllers.firstIndex(of: viewController) else { return nil } return index == 0 ? nil : parent.controllers[index-1] } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { guard let index = parent.controllers.firstIndex(of: viewController) else { return nil } return index == parent.controllers.count-1 ? nil : parent.controllers[index+1] } } } // 使用示例 .sheet(isPresented: $showSheet) { PageViewController(controllers: [ UIHostingController(rootView: TextField("Venue name", text: $text, axis: .vertical)), UIHostingController(rootView: TextField("Venue name", text: $text, axis: .vertical)) ]) .presentationDetents([.medium]) }
补充说明:该问题属于iOS17 SwiftUI的已知bug,目前苹果尚未修复,上述方法可临时解决问题,后续可关注iOS版本更新后的修复情况。
内容的提问来源于stack exchange,提问作者jalone
相关产品推荐
相关产品推荐

