keyboardWillShow 中的流畅动画不适用于 UITextView

Smooth animation in keyboardWillShow doesn't work with UITextView

对我有用的解决方案

经过几天的努力,我终于设法找到了视图动画问题的修复方法。对我来说 keyboardWillChangeFrameNotification 有效。该解决方案在以下线程中讨论:

Move textfield when keyboard appears swift

我在堆栈视图和文本视图中嵌入了一堆视图。我给定的文本视图高度 <= 120。在 keyboardWillShow 视图中,尽管根据需要添加了代码,但视图没有动画。我玩过持续时间值,但结果都是一样的。我想知道这是否是由于文本视图?如何解决?

@objc func keyboardWillShow(notification:NSNotification) {

    guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }

    let keyboardScreenEndFrame = keyboardValue.cgRectValue
    let keyboardFrame = view.convert(keyboardScreenEndFrame, from: view.window)

    if #available(iOS 11.0, *) {
        scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardFrame.height - view.safeAreaInsets.bottom, right: 0)
    } else {
        scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardFrame.height, right: 0)
    }

    scrollView.scrollIndicatorInsets = scrollView.contentInset

    let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height + keyboardFrame.height - scrollView.bounds.size.height)
    scrollView.setContentOffset(bottomOffset, animated: true)

    UIView.animate(withDuration: 0.5, animations: { () -> Void in
        self.view.layoutIfNeeded()
    })
}

===

   extension FirstViewController: UITextViewDelegate {

    func textViewDidChange(_ textView: UITextView) {

        let estimatedSize = textView.sizeThatFits(textView.frame.size)

        if estimatedSize.height > textViewMaxHeight {
            if estimatedSize.height - textViewMaxHeight < textView.font!.lineHeight && !didExpandTextView {

                didExpandTextView = true

                var contentInset:UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: self.savedKbHeight, right: 0.0)

                if let v = self.tabBarController?.tabBar {
                    contentInset.bottom -= v.frame.height
                }

                scrollView.contentInset = contentInset
                scrollView.scrollIndicatorInsets = contentInset

                if textView.isFirstResponder {
                    let fr = textView.frame
                    scrollView.scrollRectToVisible(fr, animated: false)
                }
            }

            textView.isScrollEnabled = true
            textView.showsVerticalScrollIndicator = true

        } else {
            if let lineHeight = textView.font?.lineHeight, Int(estimatedSize.height / lineHeight) != numberOfLines {
                numberOfLines = Int(estimatedSize.height / textView.font!.lineHeight)

                var contentInset:UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: self.savedKbHeight, right: 0.0)

                print("contentInset: \(contentInset)")
                scrollView.contentInset = contentInset
                scrollView.scrollIndicatorInsets = contentInset

                if textView.isFirstResponder {
                    let fr = textView.frame
                    scrollView.scrollRectToVisible(fr, animated: false)
                }

                didExpandTextView = false
            }

            textView.isScrollEnabled = false
        }
    }

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

试试这个方法:

    func textViewDidChange(_ textView: UITextView) {

        let estimatedSize = textView.sizeThatFits(textView.frame.size)

        textView.isScrollEnabled = estimatedSize.height > textViewMaxHeight

        if !textView.isScrollEnabled {
            let maxBottom = self.view.frame.height - self.savedKbHeight

            // Use following line if you have Extended Edges set
            // let maxBottom = self.view.frame.height - self.savedKbHeight - topLayoutGuide.length - bottomLayoutGuide.length

            var r = self.textView.frame
            r.size.height = estimatedSize.height
            let tvBottom = self.scrollView.convert(r, to: self.view).maxX
            if tvBottom > maxBottom {
                self.scrollView.scrollRectToVisible(r, animated: true)
            }
        }
    }

编辑 注意:这不是生产就绪代码。影响布局/定位的因素很多,不能保证 "dropping this in" 在所有情况下都有效。