当iOS11上出现键盘时,UITableView将键盘的高度添加到contentSize

时间:2019-02-26 10:58:33

标签: ios swift uitableview uiscrollview ios11

我正在进行的聊天应在iOS 11和12上进行。在iOS 12上,一切正常。但是,在iOS 11上,我出现一个问题,即键盘出现后,表视图内容的大小就会增加(没有单元格)。额外的高度与键盘的高度相匹配。

演示

这里是一个演示,左侧为iOS 11,右侧为iOS 12。在iOS 12上,一切正常。出现键盘时,请注意iOS 11上表格视图的底部。

Table view content size iOS 11 Table view content size iOS 12

视图/视图控制器层次结构设置

- =视图控制器
+ =查看

- UINavigationViewController
    - UIViewController // Controlling contentInsets, contentOffset of the tableView
        + UIView
        - UITableViewController
            + UITableView
        - UIViewController // Controlling the text input bar at the bottom
            + ... // Other views
            + UITextView

布局约束

表视图的锚点等于其父视图的锚点。如此全屏显示,忽略了安全区域。因此,当键盘出现时,框架不会改变,但底部内容会插入。

更多详细信息

我设置了tableView.contentInsetAdjustmentBehavior = .never

这是当键盘出现时如何计算表格视图的插入量和偏移量的方法。这很复杂,因为在几种情况下应该有不同的行为。当键盘消失以及文本输入的高度发生变化时,会有类似的复杂计算。我一直想根据视图框架的变化向上或向下滚动表格视图。

@objc func handleKeyboardWillShowNotification(_ notification: NSNotification) {
    let frameEnd: CGRect = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue ?? .zero
    let keyboardHeight = frameEnd.height
    let contentHeight = tableView.contentSize.height
    let visibleTableViewHeight = tableView.frame.height - (tableView.contentInset.top + tableView.contentInset.bottom)
    let distanceToScroll = (keyboardHeight - view.safeAreaInsets.bottom)
    var y: CGFloat = 0
    if contentHeight > visibleTableViewHeight {
        y = tableView.contentOffset.y + distanceToScroll
    } else {
        let diff = visibleTableViewHeight - contentHeight
        let positionAtKeyboard = distanceToScroll - tableView.contentInset.top - diff
        y = positionAtKeyboard < tableView.contentInset.top ? -tableView.contentInset.top : positionAtKeyboard
    }
    let contentOffset = CGPoint(x: 0, y: y)
    tableView.contentInset.bottom = keyboardHeight + inputBar.frame.height
    tableView.scrollIndicatorInsets = tableView.contentInset
    tableView.setContentOffset(contentOffset, animated: false)
}

我也在不同的屏幕尺寸上进行了尝试,它总是向contentSize添加一个与键盘高度完全匹配的数量。

3 个答案:

答案 0 :(得分:0)

首先,您不必进行不必要的计算 只需计算键盘高度,然后将键盘向上移动即可。

快速版本:

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height + 10, right: 0)
        UIView.animate(withDuration: 0.25) {
            self.tableView.layoutIfNeeded()
            self.view.layoutIfNeeded()
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {

    self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    UIView.animate(withDuration: 0.5) {
        self.tableView.layoutIfNeeded()
        self.view.layoutIfNeeded()
    }
}

Objective-C版本:

- (void)keyboardWillShow:(NSNotification *)notification
{
    NSDictionary *keyInfo = [notification userInfo];
    CGRect keyboardFrame = [[keyInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

    self.tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardFrame.size.height + 10, 0);

    [UIView animateWithDuration:0.2 animations:^{
        [self.tableView layoutIfNeeded];
        [self.view layoutIfNeeded];
    } completion:nil];
}

- (void) keyboardWillHide:  (NSNotification *) notification
{
    self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    [UIView animateWithDuration:0.2 animations:^{
        [self.view layoutIfNeeded];
    } completion:nil];
}

如果您遇到任何困难,请告诉我。 这对我很有效

答案 1 :(得分:0)

您可以使用以下代码进行键盘的隐藏和显示。

//显示键盘。

@objc func keyboardWillAppear(_ notification: NSNotification) {
    if let newFrame = (notification.userInfo?[ UIResponder.keyboardFrameEndUserInfoKey ] as? NSValue)?.cgRectValue {
        if self.tableView.contentInset.bottom == 0 {
            let insets: UIEdgeInsets = UIEdgeInsets( top: 0, left: 0, bottom: newFrame.height, right: 0 )
            self.tableView.contentInset = insets
            self.tableView.scrollIndicatorInsets = insets
            UIView.animate(withDuration: 0.1) {
                self.view.layoutIfNeeded()
            }
        }
    }
}

//隐藏键盘。

@objc func keyboardWillDisappear(_ notification: NSNotification) {
    if self.tableView.contentInset.bottom != 0 {
        self.tableView.contentInset = UIEdgeInsets( top: 0, left: 0, bottom: 0, right: 0 )
        self.tableView.scrollIndicatorInsets = UIEdgeInsets( top: 0, left: 0, bottom: 0, right: 0 )
        UIView.animate(withDuration: 0.1) {
            self.view.layoutIfNeeded()
        }
    }
}

这对我有用。

答案 2 :(得分:0)

解决方法

这不是专门回答原始问题的方法,但是对于那些没有半透明键盘和输入视图的人来说,这可能是一个解决方案。

我可以通过更改约束而不设置底部插图来解决此问题。最初,表视图的底部约束设置为超级视图的底部(基本上是屏幕的底部)。因此,当键盘出现时,我没有更改表格视图的框架,而是底部的插图。这显然不能正常工作。

现在,我已将表视图的底部约束设置为输入视图的顶部(黑条),并将底部插图设置为零。由于输入视图在出现键盘时会向上移动,因此它将更改表格视图的框架,并且底部插图保持为零。我仍然设置内容偏移量,因为在不同情况下我需要特定的行为,仅此而已。

这仅在我的情况下有效,因为我既没有半透明的输入栏,也没有键盘,也不需要在其后面显示模糊的内容。