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" 在所有情况下都有效。
对我有用的解决方案
经过几天的努力,我终于设法找到了视图动画问题的修复方法。对我来说 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" 在所有情况下都有效。