当键盘出现时,按固定常量平滑向上滚动表格视图,以便最后一个单元格仍然可见

问题描述

键盘出现时,我将最底部的视图向上移动一个常数。但由于这个原因, UITableView 的高度也降低了,以前可见的单元格不再可见。我想要做的是将表格视图向上滚动一个等于键盘高度的高度,这样至少最后的消息会像键盘出现之前一样可见。

左侧图像中半可见的最后一个黄色单元格也应该像右侧那样可见。

我认为以等于键盘高度的偏移量滚动表格视图应该可行。但是我找不到任意滚动 tableview 的方法。我尝试弄乱内容偏移的 y 值,但这会产生奇怪的行为。我也非常感谢过渡是否平滑,以便表格视图单元格看起来像随着键盘一起向上移动。类似于所有其他聊天应用程序如何设置这种转换。

编辑 3

好的,所以我已经计算出键盘出现和消失的数学方法。但是在跟随动画曲线的其余部分之前,动画仍然会跳跃一点。我该如何解决

NotificationCenter.default.addobserver(self,selector: #selector(keyboardNotification),name: NSNotification.Name.UIKeyboardWillChangeFrame,object: nil)

extension discussionsViewController {
    @objc func keyboardNotification(notification: NSNotification) {
        guard let userInfo = notification.userInfo else { return }
        
        let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame?.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.Animationoptions.curveEaseInOut.rawValue
        let animationCurve:UIView.Animationoptions = UIView.Animationoptions(rawValue: animationCurveRaw)
        
 let offset = -1 * (endFrame?.size.height ?? 0.0)
        
        if endFrameY >= UIScreen.main.bounds.size.height {
    
            self.discussionsMessageBoxBottomAnchor.constant = 0.0
            let yOffset = discussionChatView.discussionTableView.contentOffset.y
            discussionChatView.discussionTableView.contentOffset.y = yOffset + 2 * offset
            
        } else {
            
            self.discussionsMessageBoxBottomAnchor.constant = offset
            let yOffset = discussionChatView.discussionTableView.contentOffset.y
            discussionChatView.discussionTableView.contentOffset.y = yOffset - offset
        }
        
        

        discussionChatView.discussionTableView.scrollIndicatorInsets = discussionChatView.discussionTableView.contentInset
        
        
        UIView.animate(
            withDuration: duration,delay: TimeInterval(0),options: animationCurve,animations: { self.view.layoutIfNeeded() },completion: nil)
    }
}

Screen recording of choppy animation


编辑 2

键盘出现时的动画现在好多了。单元格以相同的动画属性向上移动。虽然当最后一个单元格在底部时仍然有一个跳跃。当键盘消失时,我仍然无法计算偏移的数学方法。以及如何让动画变得更流畅。

extension discussionsViewController {
    @objc func keyboardNotification(notification: NSNotification) {
        guard let userInfo = notification.userInfo else { return }
        
        let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame?.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.Animationoptions.curveEaseInOut.rawValue
        let animationCurve:UIView.Animationoptions = UIView.Animationoptions(rawValue: animationCurveRaw)
        
        let offset = -1 * (endFrame?.size.height ?? 0.0)
        
        if endFrameY >= UIScreen.main.bounds.size.height {
    
            self.discussionsMessageBoxBottomAnchor.constant = 0.0
            //STILL NOT AS EXPECTED
            let yOffset = discussionChatView.discussionTableView.contentOffset.y
            discussionChatView.discussionTableView.contentOffset.y = yOffset - offset
            
        } else {
            
            self.discussionsMessageBoxBottomAnchor.constant = offset
            let yOffset = discussionChatView.discussionTableView.contentOffset.y
            discussionChatView.discussionTableView.contentOffset.y = yOffset - offset
        }
        
        
        UIView.animate(
            withDuration: duration,completion: nil)
    }
}

编辑 1

这是按预期移动单元格,但动画不连贯,单元格丢失且与动画的其余部分不符。有没有办法覆盖动画曲线和其他属性?我应该把它放在 UIView.animate 里面,并为 setContentOffset 设置动画假吗?我不知道如何完全解决这个问题。

if endFrameY >= UIScreen.main.bounds.size.height {
    self.discussionsMessageBoxBottomAnchor.constant = 0.0
    self.discussionChatView.discussionTableView.contentInset.bottom = 0
} else {
    let offset = -1 * (endFrame?.size.height ?? 0.0)
    self.discussionsMessageBoxBottomAnchor.constant = offset
    
//            discussionChatView.discussionTableView.contentInset.bottom = -1 * offset
    
    let yOffset = discussionChatView.discussionTableView.contentOffset.y
    
    discussionChatView.discussionTableView.setContentOffset(CGPoint(x: 0,y: yOffset - offset),animated: true)
}

解决方法

你差点就明白了。

滚动表格视图不起作用,因为它已经位于内容的边缘,但您可以使用 contentInset 来“填充”内容。

您要做的是计算键盘进入表格视图的距离,并将该值设置为 contentInset.bottom。这将在表格视图的底部添加一个“空白区域”。

我不知道这是否会自动滚动您的视图,但如果不是这种情况,那么您可以使用 setContentOffset(_:animated:)。在桌子上。