我有一个表单,包含多个文本字段。用户像往常一样输入字段。但是用户还可以选择双击文本字段,这会呈现一个模态视图控制器,允许用户从与该字段相关的多个选项中进行选择。
我是否可以以某种方式将模态视图“覆盖”在键盘上,这样当它被解除时,键盘仍然处于活动状态,以供之前已经是第一响应者的字段使用?
目前,当模态框出现时,键盘会关闭,并在模态框消失时重新出现。我认为这看起来很笨拙和分散注意力。我希望能简化它,并减少屏幕上的动画数量。
我有一个表单,包含多个文本字段。用户像往常一样输入字段。但是用户还可以选择双击文本字段,这会呈现一个模态视图控制器,允许用户从与该字段相关的多个选项中进行选择。
我是否可以以某种方式将模态视图“覆盖”在键盘上,这样当它被解除时,键盘仍然处于活动状态,以供之前已经是第一响应者的字段使用?
目前,当模态框出现时,键盘会关闭,并在模态框消失时重新出现。我认为这看起来很笨拙和分散注意力。我希望能简化它,并减少屏幕上的动画数量。
编辑:我已经更新了这个答案,以适应iOS 12和Swift。修订后的示例项目(包含新的Swift和更新的Objective-C实现)在这里。
您可以创建一个新的UIWindow
,并在隐藏键盘窗口的同时将其放置在默认窗口上方。
我在Github上有一个示例项目here,但是基本过程如下。
UIViewController
类。我称之为OverlayViewController
。按您的要求设置相应的视图。根据您的问题,您需要传回一些选项,因此我制作了一个委托协议OverlayViewControllerDelegate
,并将主窗口的根视图控制器(类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?
UITextField
上添加一个UITapGestureRecognizer
。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
具有内置的手势识别器,因此我们需要允许多个 UIGestureRecognizer
同时操作。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()
来实现,但现在将其设置为关键会关闭键盘。此外,键盘的窗口现在具有非标准的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
}
[self.overlayWindow setWindowLevel:UIWindowLevelAlert];
[self.overlayWindow makeKeyAndVisible];
请放置以下代码:
NSArray *windows = [[UIApplication sharedApplication] windows];
UIWindow *lastWindow = (UIWindow *)[windows lastObject];
[self.overlayWindow setWindowLevel:lastWindow.windowLevel + 1];
[self.overlayWindow setHidden:NO];
我现在无法尝试这个,但已经为其他目的实现了类似的功能。在呈现模态控制器的操作中,我假设手势识别器或委托方法,首先截取屏幕截图并将其放置在当前子视图上方的imageView
中。稍后返回时,只需删除imageView
即可。
听起来可能很疯狂,但我记得曾经在转换过程中键盘移动导致类似的笨拙行为。实现起来并不难。
如果你尝试有困难,也许有人会提供一些代码。我可以稍后引用自己的工作并添加一个例子,但现在不行。
UITextField、UITextView或UISearchBar
,它们应该是第一响应者,并且它们应该在视图中可见。这意味着响应的视图应该在窗口的顶层级别层次结构中。ViewController.view
作为子视图添加到self.view
中并进行动画,而不是展示一个ViewController
。您可以访问iOS键盘框架。
您需要实现代码来监听键盘通知(如UIKeyboardWillShowNotification和UIKeyboardWillChangeFrameNotification)。通知将向您发送有关键盘框架的信息。
请查看“键盘通知用户信息键”在windows reference中的描述。
对于您的目的,您会发现以下内容很有用:
UIKeyboardBoundsUserInfoKey用于标识NSValue对象的键,该对象包含一个CGRect,用于在窗口坐标中标识键盘的边界矩形。此值足以获取键盘的大小。如果要获取键盘在屏幕上的原点(动画前或后),请使用通过UIKeyboardCenterBeginUserInfoKey或UIKeyboardCenterEndUserInfoKey常量从用户信息字典中获取的值。
有了键盘框架的信息,您就可以显示模态视图。
只需在您的文本字段中添加一个轻拍手势和一个UITextfield *flagTextfield;
UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(DoubleTapMethod:)];
doubleTap.numberOfTapsRequired = 2;
[self.txtTest addGestureRecognizer:doubleTap];
-(void)DoubleTapMethod:(UITapGestureRecognizer *)gesture
{
[flagTextfield resignFirstResponder];
NSLog(@"DoubleTap detected");
//Set your logic on double tap of Textfield...
//presents a modal view controller
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
flagTextfield = textfield;
}