11

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

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

现在,键盘在模态出现时消失,并在模态消失时重新出现。在我看来它很笨重,而且让人分心。希望简化它,并减少屏幕上的动画数量。

4

6 回答 6

17

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


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


将新 UIWindow 覆盖在现有 UIWindow 上的动画示例


我在Github 上有一个示例项目,但基本过程如下。

  • 为您的模态视图创建一个新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
}
  • 覆盖窗口应该消失,您的原始窗口应该出现在与以前相同的位置的键盘上。
于 2014-08-12T14:41:46.503 回答
3

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

听起来可能很疯狂,但我记得在过渡期间键盘移动会导致类似的笨拙行为的过渡中这样做了。实施起来并不难。

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

于 2014-08-11T12:43:26.440 回答
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];
于 2017-06-28T08:51:20.023 回答
1

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

如果您不需要此效果,ViewController您可以添加ViewController.view作为带有动画的 self.view 的子视图,而不是呈现。

于 2014-08-07T05:59:24.523 回答
1

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

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

请查看windows 参考中“键盘通知用户信息键”的描述。

你会发现对你有用的目的:

UIKeyboardBoundsUserInfoKey一个 NSValue 对象的键,它包含一个 CGRect,它在窗口坐标中标识键盘的边界矩形。该值足以获得键盘的大小。如果要获取屏幕上键盘的来源(动画之前或之后),请使用通过 UIKeyboardCenterBeginUserInfoKey 或 UIKeyboardCenterEndUserInfoKey 常量从用户信息字典中获取的值。

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

于 2014-08-11T11:06:03.030 回答
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;
}
于 2014-08-11T13:57:13.657 回答