将键盘移至 TabViewController TabBar 上方

Move keyboard above TabViewController TabBar

是否可以将键盘向上移动,使其不覆盖 UITabViewController 的 TabBar?

在评论中获得更多上下文后更新

如果您主要关心的是让用户关闭键盘,则平台上通常应用一些众所周知的模式:

关于 UI 的假设 (源自您的评论)
- UITableView 作为主要内容

要使键盘可关闭,您可以在 UIScrollView 上使用名为 .keyboardDismissMode 的 属性。 (UITableView 派生自 UIScrollView,因此它继承了 属性。)

此 属性 的默认值为 .none。将其更改为 .onDrag.interactive。有关后两个选项之间的差异,请参阅文档。 在幕后,UIKitUIScrollView 实例和任何传入键盘之间建立连接。这允许用户通过与滚动视图交互来 "swipe away" 键盘。

请注意,要使此功能发挥作用,您的 UIScrollView 需要可滚动。要了解 'scrollable' 在此上下文中的含义,请 see this gist.

如果您的 tableView 的行很少或没有行,则它可能不是本机可滚动的。考虑到这一点,设置 tableView.alwaysBounceVertical = true。这将确保无论 table.

中的行数如何,您的用户都可以关闭键盘

大多数处理键盘关闭的流行应用程序也可以通过点击与键盘部分重叠的内容(在您的情况下为 tableView)来关闭键盘。要启用此功能,您只需在视图上安装 UITapGestureRecognizer 并在其操作方法中关闭键盘:

class MyViewController: UIViewController {
  func viewDidLoad() {
    super.viewDidLoad()

    let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    view.addGestureRecognizer(tapRecognizer)
  }
}

//MARK: - Tap handling
fileprivate extension MyViewController {
  @objc func handleTap() {
    if searchBar.isFirstResponder {
      searchBar.resignFirstResponder()
    }

    // Alternative
    // view.endEditing(true)
  }
}
// -


旧答案

是的,您实际上可以在不使用 private API.

的情况下执行此操作 免责声明

你真的应该考虑一下你是否真的想这样做。在几乎每个用例中打开键盘都应该创建一个新的 "context" 编辑模态 "blocks" 其他上下文(例如 UITabBarController 及其 UITabBar 提供的导航上下文)。我想有人可以指出,用户可以通过与可能存在的 UINavigationBar 交互来离开编辑上下文,这通常 not 被键盘阻止。但是,这是整个系统的已知交互。另一方面,Not 在显示键盘时阻止 UITabBarUIToolbarnot。也就是说,使用下面的代码将键盘向上移动,但批判性地审查您正在创建的用户体验。我并不是说向上移动键盘 从来没有 有意义,但您应该真正知道自己在这里做什么。老实说,它看起来也有点不稳定,让键盘浮动在标签栏上方。

代码

extension Sequence {
  func last(where predicate: (Element) throws -> Bool) rethrows -> Element? {
    return try reversed().first(where: predicate)
  }
}

// Using `UIViewController` as an example. You could and actually should factor this logic out.
class MyViewController: UIViewController {
  deinit {
    NotificationCenter.default.removeObserver(self)
  }

  func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: .UIKeyboardWillHide, object: nil)
  }
}

//MARK: - Keyboard handling
extension MyViewController {
  private var keyboardOffset: CGFloat {
    // Using a fixed value of `49` here, since that's what `UITabBar`s height usually is.
    // You should probably use something like `-tabBarController?.tabBar.frame.height`.
    return -49
  }

  private var keyboardWindowPredicate: (UIWindow) -> Bool {
    return { [=11=].windowLevel > UIWindowLevelNormal }
  }

  private var keyboardWindow: UIWindow? {
    return UIApplication.shared.windows.last(where: keyboardWindowPredicate)
  }

  @objc fileprivate func keyboardWillShow(notification: Notification) {
    if let keyboardWindow = keyboardWindow {
      keyboardWindow.frame.origin.y = keyboardOffset
    }
  }

  @objc fileprivate func keyboardWillHide(notification: Notification) {
    if let keyboardWindow = keyboardWindow {
      keyboardWindow.frame.origin.y = 0
    }
  }
}
// -

注意

请注意,如果您使用 .UIKeyboardWillShow.UIKeyboardWillHide 通知来说明视图中的键盘(例如,设置 UIScrollView 插入),您还必须考虑移动键盘的任何额外偏移 window.

这有效并通过 iOS 11 进行了测试。但是,不能保证 UIKit 团队不会更改 windows 的顺序或其他破坏的顺序这在未来的版本中。同样,您没有使用任何私有 API,因此 AppStore 审查不应该处于危险之中,但是您 正在 做一些您不应该使用框架做的事情, 以后总是会过来咬你一口。