iOS 16无法在不关闭键盘时弹出UIViewController的问题排查
问题解答
关于Xcode Beta版本的问题
Xcode 14 Beta作为预览版本,确实存在UIKit内部窗口结构的临时调整,导致UIRemoteKeyboardWindow无法被检测到;而稳定版Xcode(如13.4.1)适配的iOS 16模拟器/正式版系统中,该窗口结构并未变更。这属于Beta版本的兼容性问题,正式发布的系统与Xcode中大概率会恢复原有逻辑,但依赖私有窗口类名始终存在风险——苹果可能随时调整内部实现,甚至导致App审核被拒,因此更推荐使用稳定的官方方案实现需求。
替代实现方案
方案1:监听键盘通知,手动调整弹窗位置
通过监听键盘弹出/收起事件,获取键盘高度后调整自定义选择器的位置,确保其显示在键盘上方:
- 添加键盘通知监听
override func viewDidLoad() { super.viewDidLoad() // 注册键盘通知 NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } // 键盘弹出时调整选择器位置 @objc private func keyboardWillShow(_ notification: Notification) { guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return } let keyboardHeight = keyboardFrame.height adjustPickerPosition(keyboardHeight: keyboardHeight) } // 键盘收起时恢复选择器位置 @objc private func keyboardWillHide(_ notification: Notification) { resetPickerPosition() }
- 设置弹窗样式并调整位置
// 弹窗时使用overCurrentContext,避免关闭键盘 self.myViewController.modalPresentationStyle = .overCurrentContext self.present(self.myViewController, animated: true) // 调整选择器到键盘上方 private func adjustPickerPosition(keyboardHeight: CGFloat) { let screenHeight = UIScreen.main.bounds.height let pickerHeight = self.myViewController.view.frame.height self.myViewController.view.frame = CGRect( x: 0, y: screenHeight - keyboardHeight - pickerHeight, width: self.myViewController.view.frame.width, height: pickerHeight ) } // 恢复选择器到屏幕底部 private func resetPickerPosition() { let screenHeight = UIScreen.main.bounds.height let pickerHeight = self.myViewController.view.frame.height self.myViewController.view.frame = CGRect( x: 0, y: screenHeight - pickerHeight, width: self.myViewController.view.frame.width, height: pickerHeight ) }
方案2:使用UIPopoverPresentationController(推荐)
如果自定义选择器是下拉样式,可利用系统的UIPopoverPresentationController,将其锚定到输入框,系统会自动适配键盘弹出时的位置:
self.myViewController.modalPresentationStyle = .popover if let popoverPC = self.myViewController.popoverPresentationController { popoverPC.sourceView = yourTextField // 指定输入框为锚点 popoverPC.sourceRect = yourTextField.bounds popoverPC.permittedArrowDirections = .up // 设置箭头方向 } self.present(self.myViewController, animated: true)
方案3:自定义承载窗口
创建层级高于键盘的独立窗口,将选择器作为窗口的根视图控制器,确保其始终显示在最上层:
// 创建自定义窗口 let pickerWindow = UIWindow(frame: UIScreen.main.bounds) pickerWindow.windowLevel = UIWindow.Level.alert + 1 // 层级高于默认弹窗与键盘 pickerWindow.rootViewController = self.myViewController pickerWindow.makeKeyAndVisible() // 在选择器关闭时销毁窗口(可在myViewController的dismiss方法中添加) // pickerWindow.isHidden = true
内容的提问来源于stack exchange,提问作者Meroelyth
相关产品推荐
相关产品推荐

