SwiftUI项目安全区机型UITextView inputAccessoryView异常求解
问题根因
异常由两处核心逻辑错误导致:
UIHostingController默认会为根视图自动添加底部安全区内边距,而inputAccessoryView的布局本身已经由系统接管安全区适配,两层偏移叠加后就会出现黄色SwiftUI视图超出红框标记的inputAccessoryView自身bounds的问题- 直接将
UIHostingController的view返回作为inputAccessoryView时,没有将hostingController挂载到当前控制器的响应链中,也没有关闭自动安全区适配,导致交互式滑动关闭键盘时,SwiftUI视图的布局更新无法和系统键盘动画同步,出现动画错位。
修复方案
按以下步骤调整即可解决问题:
- 不要直接返回
UIHostingController的view作为inputAccessoryView,自定义一个重写了intrinsicContentSize的容器视图作为inputAccessoryView的载体,开启flexibleHeight自动适配 - 初始化
UIHostingController后关闭自动安全区适配:iOS16+设置ignoresSafeAreaEdges = .all,低版本清空additionalSafeAreaInsets,同时关闭系统最小边距适配 - 通过响应链找到输入框所在的父控制器,将
UIHostingController添加为该控制器的子控制器,保证布局、动画事件正常传递 - 给作为工具栏的SwiftUI视图添加
.ignoresSafeArea(),避免内部布局额外产生安全区偏移 - 放弃手动计算frame的方式,用Auto Layout将hostingController的view贴紧容器四边,由系统自动计算尺寸
修正后完整代码
首先添加UIView的父控制器查找扩展、自定义inputAccessoryView容器:
extension UIView { var parentViewController: UIViewController? { var responder: UIResponder? = self while let currentResponder = responder { if let viewController = currentResponder as? UIViewController { return viewController } responder = currentResponder.next } return nil } } class KeyboardAccessoryContainer: UIView { override var intrinsicContentSize: CGSize { let contentHeight = subviews.first?.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height ?? 0 return CGSize(width: UIView.noIntrinsicMetric, height: contentHeight) } }
修改UITextViewWrapper实现:
struct UITextViewWrapper: UIViewRepresentable { @Binding var text: String func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.text = text textView.keyboardDismissMode = .interactive textView.alwaysBounceVertical = true textView.inputAccessoryView = makeKeyboardBar(for: textView) textView.delegate = context.coordinator textView.becomeFirstResponder() return textView } func updateUIView(_ uiView: UITextView, context: Context) {} class Coordinator: NSObject, UITextViewDelegate { let parent: UITextViewWrapper init(_ parent: UITextViewWrapper) { self.parent = parent } func textViewDidChange(_ textView: UITextView) { parent.text = textView.text } } func makeCoordinator() -> Coordinator { Coordinator(self) } private func makeKeyboardBar(for textView: UITextView) -> UIView { let container = KeyboardAccessoryContainer() container.backgroundColor = .clear container.autoresizingMask = .flexibleHeight let toolbarView = ColorView().ignoresSafeArea() let hostingController = UIHostingController(rootView: toolbarView) // 关闭HostingController自动安全区适配 hostingController.viewRespectsSystemMinimumLayoutMargins = false hostingController.additionalSafeAreaInsets = .zero if #available(iOS 16.0, *) { hostingController.ignoresSafeAreaEdges = .all } guard let hostView = hostingController.view else { return container } hostView.backgroundColor = .clear hostView.translatesAutoresizingMaskIntoConstraints = false // 挂载子控制器保证事件正常传递 if let parentVC = textView.parentViewController { parentVC.addChild(hostingController) container.addSubview(hostView) NSLayoutConstraint.activate([ hostView.leadingAnchor.constraint(equalTo: container.leadingAnchor), hostView.trailingAnchor.constraint(equalTo: container.trailingAnchor), hostView.topAnchor.constraint(equalTo: container.topAnchor), hostView.bottomAnchor.constraint(equalTo: container.bottomAnchor) ]) hostingController.didMove(toParent: parentVC) } // 测试边框 hostView.layer.borderWidth = 1 hostView.layer.borderColor = UIColor.red.cgColor return container } }
ColorView和ContentView无需额外修改,调整后黄色工具栏视图会完全贴合inputAccessoryView的范围,交互式下滑关闭键盘时,工具栏动画会和键盘完全同步,不会出现偏移、错位问题。
内容的提问来源于stack exchange,提问作者FE_Tech
相关产品推荐
相关产品推荐

