键盘处于活动状态时显示模态视图控制器

时间:2014-08-05 03:21:46

标签: ios uitextfield first-responder presentviewcontroller

所以我基本上有一个表单,由几个文本字段组成。用户像往常一样键入字段。但是用户还可以选择双击文本字段,该文本字段提供模态视图控制器,允许用户从与该字段相关的多个选项中进行选择。

我可以以某种方式在键盘上方显示模态,这样当它被解除时,键盘仍然在我呈现模态之前已经是第一响应者的字段处于活动状态吗?

现在,键盘在模态出现时解散,并在模态被解除时重新出现。它看起来很笨重,而且分散注意力。希望精简它,并减少屏幕上的动画量。

6 个答案:

答案 0 :(得分:11)

编辑:我已经为iOS 12和Swift更新了这个答案。修订后的示例项目(包含新的Swift和更新的Objective-C实现)是here


您可以创建一个新的UIWindow并将其放在默认窗口中,同时隐藏键盘的窗口。


Animated example of overlaying a new UIWindow over the existing one


我在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有一个内置的手势识别器,因此我们需要允许多个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
}
  • 叠加窗口应该消失,原始窗口应该出现,键盘与以前位置相同。

答案 1 :(得分:3)

我现在无法尝试,但为了其他目的已经实现了类似的功能。在用于呈现模态控制器的动作中,我假设手势识别器或委托方法,首先截取屏幕截图并将其放在当前子视图上的imageView中。稍后返回时,只需删除imageView

可能听起来很疯狂,但我记得在转换期间键盘移动导致类似笨重行为的过渡时已经做到了这一点。实施起来并不困难。

如果您在尝试时遇到问题,也许有人会提供一些代码。我可以稍后参考我自己的工作并添加一个例子,但不是现在。

答案 2 :(得分:3)

@Rob Bajorek的答案很棒。 对于iOS 9,10,有一些小改动。
 而不是代码:

[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];

答案 3 :(得分:1)

为了使键盘显示任何文本接受字段,UITextField or UITextView or UISearchBar应该是第一个响应者,它们应该在视图中可见。意义响应视图应位于窗口的顶级层次结构中。

如果您不需要此效果,您可以添加ViewController作为自我视图的子视图,而不是呈现ViewController.view

答案 4 :(得分:1)

您可以访问iOS中的键盘框架。

您需要实现代码来收听键盘通知(例如UIKeyboardWillShowNotification和UIKeyboardWillChangeFrameNotification)。通知将向您发送有关键盘框架的信息。

Giva查看windows reference中“键盘通知用户信息键”的说明。

你会觉得有用的目的:

  

UIKeyboardBoundsUserInfoKey 包含CGRect的NSValue对象的键,该CGRect标识了边界的矩形   窗口坐标中的键盘。该值足以获得   键盘的大小。如果你想得到的起源   屏幕上的键盘(动画之前或之后)使用值   通过用户信息字典获得   UIKeyboardCenterBeginUserInfoKey或UIKeyboardCenterEndUserInfoKey   常数。

使用键盘框架的信息,您可以在那里显示模态视图。

答案 5 :(得分:1)

只需在文本字段和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;
}