编辑:我已经为 iOS 12 和 Swift 更新了这个答案。修改后的示例项目(包含新的 Swift 和更新的 Objective-C 实现)是here。
您可以创建一个新的UIWindow 并将其放置在默认窗口上,同时隐藏键盘窗口。
我在 Github here 上有一个示例项目,但基本流程如下。
- 为您的模态视图创建一个新的
UIViewController 类。我打电话给我的OverlayViewController。根据需要设置相应的视图。根据您的问题,您需要回传一些选项,因此我创建了一个委托协议 OverlayViewController,并将主窗口的根视图控制器(类 ViewController)作为我们的委托。
protocol OverlayViewControllerDelegate: class {
func optionChosen(option: YourOptionsEnum)
}
class ViewController: UIViewController {
/// The text field that responds to a double-tap.
@IBOutlet private weak var firstField: UITextField!
/// A simple label that shows we received a message back from the overlay.
@IBOutlet private weak var label: UILabel!
/// The window that will appear over our existing one.
private var overlayWindow: UIWindow?
- 将
UITapGestureRecognizer 添加到您的UITextField。
override func viewDidLoad() {
super.viewDidLoad()
// Set up gesture recognizer
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapRecognizer.numberOfTapsRequired = 2
doubleTapRecognizer.delegate = self
firstField.addGestureRecognizer(doubleTapRecognizer)
firstField.becomeFirstResponder()
}
-
UITextField 内置了手势识别器,所以我们需要允许多个UIGestureRecognizers 同时操作。
extension ViewController: UIGestureRecognizerDelegate {
// Our gesture recognizer clashes with UITextField's.
// Need to allow both to work simultaneously.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
-
这是有趣的部分。 当手势识别器被触发时,创建新的
UIWindow,将您的OverlayViewController 指定为根视图控制器,并显示它。请注意,我们将窗口级别设置为UIWindowLevelAlert,因此它将出现在前面。但是,尽管有警报窗口级别,键盘仍然会在前面,所以我们也必须手动隐藏它的窗口。
重要的是不要将新的UIWindow 设置为键或更改UITextField 的第一响应者,否则键盘将被关闭。
以前(在 iOS 10 之前?)我们可以使用 overlayWindow.makeKeyAndVisible(),但现在将其设置为 key 会关闭键盘。此外,键盘窗口现在有一个非标准的UIWindow.Level 值,位于每个公开定义的值前面。我通过在层次结构中找到键盘的窗口并将其隐藏来解决这个问题。
@objc func handleDoubleTap() {
// Prepare the overlay window
guard let overlayFrame = view?.window?.frame else { return }
overlayWindow = UIWindow(frame: overlayFrame)
overlayWindow?.windowLevel = .alert
let overlayVC = OverlayViewController.init(nibName: "OverlayViewController", bundle: nil)
overlayWindow?.rootViewController = overlayVC
overlayVC.delegate = self
// The keyboard's window always appears to be the last in the hierarchy.
let keyboardWindow = UIApplication.shared.windows.last
keyboardWindow?.isHidden = true
}
- 覆盖窗口现在是原始窗口。用户现在可以选择您在叠加视图中构建的任何选项。在您的用户选择一个选项后,您的代理应采取您想要的任何操作,然后关闭覆盖窗口并再次显示键盘。
func optionChosen(option: YourOptionsEnum) {
// Your code goes here. Take action based on the option chosen.
// ...
// Dismiss the overlay and show the keyboard
overlayWindow = nil;
UIApplication.shared.windows.last?.isHidden = false
}
- 覆盖窗口应该会消失,您的原始窗口应该会出现,并且键盘的位置与之前相同。