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

时间:2019-11-29 10:23:36

标签: ios swift uiscrollview uikeyboard

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

UIViewController    (1)
  - NavigationBar   (2)
  - UIScrollView    (2)
    - UIView        (3)
      - UITextField (4)
      - UITextField (4)
      - UITextField (4)
      - UITextField (4)
      - UIButton    (4)
  • 级别4的所有元素相互垂直约束,间距为16。
  • 级别4的第一个和最后一个元素被限制在UIView(3)的顶部和底部。
  • UIView(3)受UIScrollView(2)的顶部和底部约束。
  • UIScrollView(2)被限制在NavigationBar的底部(2)和超级视图的底部(1
  • (当然也有必要的水平约束!)

UIView(3)具有以下约束:

  • 所有子视图的领先约束为0。
  • 所有子视图的跟踪约束均为0。
  • UIButton的底部空格为24(应增加 some 额外的间距)
  • 顶部24到顶部UITextField(顶部间距)
  • 超级视图(UIScrollView)的顶部空间0
  • 0到superView(UIScrollView)的底部空间
  • “等于宽度-减去32”到NavigationBar(因此-固定宽度)

在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(足够)。我调试了,就是这种情况:

  • 常规键盘:height = 216
  • 带有建议栏的常规键盘:height = 260
  • 带有建议栏的iPhone X键盘:height = 291

尽管建议栏可能是我的问题,但我不是。

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

  • 这不是keyboardWillShowNotification我尝试过的keyboardDidShowNotification,这没什么区别。
  • 这不是keyboardFrameEndUserInfoKey我尝试过的keyboardFrameBeginUserInfoKey,这没什么区别。

我在这里想念什么?

1 个答案:

答案 0 :(得分:0)

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

但是,我通过使用UIScrollView内的UIStackView得到了预期的行为。我以this article作为参考。


用户界面布局

  • UIViewController(1)
    • NavigationBar(2)
    • UIScrollView(2)
    • UIStackView(3)
      • UITextField(4)
      • UITextField(4)
      • UITextField(4)
      • UITextField(4)
      • UIButton(4)

UIScrollView

  • ScrollView的leadingtrailing 16 约束。
  • ScrollView的top被导航栏底部的 0 约束。
  • ScrollView的bottom受到SuperView底部的 0 约束。

UIStackView

  • StackView的leadingtrailing的滚动视图受 0 约束。
  • StackView与scrollView的宽度相等。
  • StackView的topbottom 24 约束到滚动视图,以获取所需的NavigationBar间距以及按钮和键盘之间的间距。
  • StackView设置为axis=verticalalignment=filldistribution=fillspacing=24

导航栏

NavigationBar是一个自定义类,它从其内容派生其高度。它没有设置高度限制,但是占位符高度为100。NavigationBar将填满整个屏幕。通过删除占位符高度,并添加低优先级(在本例中为1优先级)的 any 高度约束,可以解决此问题。


应用键盘嵌入的初始代码现在可以使用。

/// 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)
    }
}