我有同样的问题,但是关于UITableView中的UITextView,所以经过一番调查,我没有找到任何“简单”的方法来修复它,所以根据接受的答案,我创建了完美的工作解决方案(也应该在UICollectionView、UIScrollView在此扩展中注释了一些更改)。
因此,为了方便重用,需要在 UIKit 之上进行一些扩展:
extension UITextView {
func scrollToCursor(animated: Bool = false, verticalInset: CGFloat = 8) {
guard let selectedTextRange = selectedTextRange else { return }
var cursorRect = caretRect(for: selectedTextRange.start)
// NOTE: can't point UIScrollView, coz on iOS 10 closest view will be UITableWrapperView
// to extend functionality for UICollectionView or plain UIScrollView it's better to search them one by one
let scrollView = findParent(of: UITableView.self) ?? self
cursorRect = convert(cursorRect, to: scrollView)
if cursorRect.origin.x.isInfinite || cursorRect.origin.y.isInfinite {
return
}
let bottomOverflow = cursorRect.maxY - (scrollView.contentOffset.y + scrollView.bounds.height - scrollView.contentInset.bottom - scrollView.contentInset.top)
if bottomOverflow > 0 {
let offset = CGPoint(x: scrollView.contentOffset.x, y: scrollView.contentOffset.y + bottomOverflow + verticalInset)
scrollView.setContentOffset(offset, animated: animated)
return
}
let topOverflow = scrollView.contentOffset.y - cursorRect.minY
if topOverflow > 0 {
let offset = CGPoint(x: scrollView.contentOffset.x, y: scrollView.contentOffset.y - topOverflow - verticalInset)
scrollView.setContentOffset(offset, animated: animated)
}
}
}
界面视图:
extension UIView {
func findParent<Parent: UIView>(of parentType: Parent.Type) -> Parent? {
return superview?.findNext(of: parentType)
}
private func findNext<Parent: UIView>(of parentType: Parent.Type) -> Parent? {
if let res = self as? Parent {
return res
}
return superview?.findNext(of: parentType)
}
}
因此,在 UITextViewDelegate 上,当文本更改时,在您需要的地方调用(可能在调度队列主异步块内 - 我为此使用 ReactiveSwift 回调):
textView.scrollToCursor()
如果您想在光标位置更改时添加向上移动(在屏幕顶部),需要在textViewDidChangeSelection
委托的方法中调用此方法(当然要检查选择长度)。