为 keyboardWillShowNotification 设置 UIScrollView 的 contentInset 无法正常工作

Setting UIScrollView's contentInset for keyboardWillShowNotification not working properly

我有一个ViewController结构如下((x)表示级别):

UIViewController    (1)
  - NavigationBar   (2)
  - UIScrollView    (2)
    - UIView        (3)
      - UITextField (4)
      - UITextField (4)
      - UITextField (4)
      - UITextField (4)
      - UIButton    (4)

UIView (3) 有以下约束:

在viewController的viewDidLoad中,我称之为:

registerForKeyboardWillShowNotification(self.scrollView)
registerForKeyboardWillHideNotification(self.scrollView)

其中 registerForKeyboard...ShowNotificationUIViewController 的扩展:

extension UIViewController
{
    /// Act when keyboard is shown, by adding contentInsets to the scrollView.
    func registerForKeyboardWillShowNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil)
    {
        _ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification,
                                                   object: nil, queue: nil)
        { notification in
            let userInfo      = notification.userInfo!
            let keyboardSize  = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
            let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top,
                                             left: scrollView.contentInset.left,
                                             bottom: keyboardSize.height,
                                             right: scrollView.contentInset.right)

            scrollView.contentInset = contentInsets
            block?(keyboardSize)
        }
    }

    /// Act when keyboard is hidden, by removing contentInsets from the scrollView.
    func registerForKeyboardWillHideNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil)
    {
        _ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification,
                                                   object: nil, queue: nil)
        { notification in
            let userInfo = notification.userInfo!
            let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
            let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top,
                                             left: scrollView.contentInset.left,
                                             bottom: 0,
                                             right: scrollView.contentInset.right)

            scrollView.contentInset = contentInsets
            block?(keyboardSize)
        }
    }
}

但是,当键盘显示时,它并没有插入 scrollView(足够)。我调试了一下,是这样的:

我一开始以为建议栏可能是问题所在,但事实并非如此。

registerForKeyboardWillShowNotification 中,我将 bottom: keyboardSize.height 更改为 bottom: keyboardSize.height + 30,这给出了完全相同的结果(我看到按钮的相同部分部分隐藏在键盘后面)。一旦我添加 50 或更多,它最终似乎会产生很小的差异。

我在这里错过了什么?

不幸的是我没能解决这个问题,我不确定为什么它没有按预期工作。

但是,我通过在 UIScrollView 中使用 UIStackView 获得了预期的行为。我使用 this article 作为参考。


UI布局

  • UIViewController (1)
    • 导航栏(2)
    • UI滚动视图 (2)
    • UI堆栈视图 (3)
      • UI文本字段 (4)
      • UI文本字段 (4)
      • UI文本字段 (4)
      • UI文本字段 (4)
      • UI按钮 (4)

UIScrollView

  • ScrollView 的leadingtrailing16 约束到superView。
  • ScrollView 的 top0 限制在导航栏的底部。
  • ScrollView 的 bottom0 限制在 superView 的底部。

UIStackView

  • StackView 的 leadingtrailing0 限制到 scrollView。
  • StackView 与 scrollView 的宽度相等。
  • StackView 的 topbottom24 限制到滚动视图,以获得所需的导航栏间距,以及按钮和键盘.
  • StackView 设置为 axis=verticalalignment=filldistribution=fillspacing=24

NavigationBar

NavigationBar 是自定义的 class,它的高度从其内容中得出。这没有设置高度限制,但占位符高度为 100。NavigationBar 将填满整个屏幕。这通过删除占位符高度,并添加具有低优先级的 any 高度约束来解决(在本例中优先级为 1)。


应用键盘插入的初始代码现在可以工作了。

/// Act when keyboard is shown, by adding contentInsets to the scrollView.
func registerForKeyboardWillShowNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil)
{
    _ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification,
                                               object: nil, queue: nil)
    { notification in
        let userInfo      = notification.userInfo!
        let keyboardSize  = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
        let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top,
                                         left: scrollView.contentInset.left,
                                         bottom: keyboardSize.height,
                                         right: scrollView.contentInset.right)

        scrollView.contentInset = contentInsets
        block?(keyboardSize)
    }
}