如何锁定 UITextView 中的插入符号 y 位置以创建打字机效果?
How to lock caret y position in UITextView to create typewriter effect?
我试图强制 UITextView
将插入符号始终保持在相同的固定高度,例如在屏幕的 1/4 处。
我的行为应该与旧打字机类似——当用户按下回车键(或到达行尾)时,文本应该向上滚动一行,插入符号应该保持在相同的 y 位置并跳转到新行的开头。
我试图这样做,但它的行为出乎意料,插入符号有时会随机跳转并且可以看到滚动,它向下滚动然后我再次使用 scrollRectToVisible
向上滚动,这似乎不是喜欢这样做的理想方式。
怎样才能达到这样的效果?任何具有类似功能的库或 pod 也将不胜感激。
func setScrollToMiddle() {
if let selectedRange = textView.selectedTextRange {
let caretRect = textView.caretRect(for: selectedRange.start)
let middleOfCaretHeight = caretRect.origin.y + (caretRect.height / 2)
let screenHeight = UIScreen.main.bounds.height
guard let kbSize = self.keyboardSize else { return }
let keyboardHeight = kbSize.height
let visibleTextAreaHeight = screenHeight - keyboardHeight - topMenuView.frame.height
let finalRectY = middleOfCaretHeight - topMenuView.frame.height - (visibleTextAreaHeight / 2)
let finalRect = CGRect(x: 0.0, y: finalRectY, width: textView.frame.width, height: visibleTextAreaHeight)
textView.scrollRectToVisible(finalRect, animated: false)
}
}
这是我会做的:
首先在view中设置这些Did load
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
textView.isEditable = true
textView.isScrollEnabled = false
}
然后添加这个扩展:
extension ViewController: UITextViewDelegate {
func trackCaret(_ textView:UITextView){
if let selectedRange = textView.selectedTextRange {
let caretRect = textView.caretRect(for: selectedRange.start)
let yPos = caretRect.origin.y - (textView.frame.height/2)
let xPos = caretRect.origin.x - (textView.frame.width/2)
textView.bounds.origin = CGPoint(x: xPos, y: yPos)
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
trackCaret(textView)
return true
}
func textViewDidBeginEditing(_ textView: UITextView) {
trackCaret(textView)
}
func textViewDidEndEditing(_ textView: UITextView) {
// If you don't need to move back to the original position you can leave this out
// textView.bounds.origin = CGPoint.zero
//or if you want smooth animated scroll back then
textView.scrollRectToVisible(CGRect(x:0,
y:0,
width: textView.bounds.width,
height: textView.bounds.height),
animated: true)
}
}
有了这个你就可以得到打字机的效果而不用到处跳了。 didendEditing 方法仅用于滚动回原点 0,0。如果您不需要这样做,请将其删除。
我试图强制 UITextView
将插入符号始终保持在相同的固定高度,例如在屏幕的 1/4 处。
我的行为应该与旧打字机类似——当用户按下回车键(或到达行尾)时,文本应该向上滚动一行,插入符号应该保持在相同的 y 位置并跳转到新行的开头。
我试图这样做,但它的行为出乎意料,插入符号有时会随机跳转并且可以看到滚动,它向下滚动然后我再次使用 scrollRectToVisible
向上滚动,这似乎不是喜欢这样做的理想方式。
怎样才能达到这样的效果?任何具有类似功能的库或 pod 也将不胜感激。
func setScrollToMiddle() {
if let selectedRange = textView.selectedTextRange {
let caretRect = textView.caretRect(for: selectedRange.start)
let middleOfCaretHeight = caretRect.origin.y + (caretRect.height / 2)
let screenHeight = UIScreen.main.bounds.height
guard let kbSize = self.keyboardSize else { return }
let keyboardHeight = kbSize.height
let visibleTextAreaHeight = screenHeight - keyboardHeight - topMenuView.frame.height
let finalRectY = middleOfCaretHeight - topMenuView.frame.height - (visibleTextAreaHeight / 2)
let finalRect = CGRect(x: 0.0, y: finalRectY, width: textView.frame.width, height: visibleTextAreaHeight)
textView.scrollRectToVisible(finalRect, animated: false)
}
}
这是我会做的:
首先在view中设置这些Did load
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
textView.isEditable = true
textView.isScrollEnabled = false
}
然后添加这个扩展:
extension ViewController: UITextViewDelegate {
func trackCaret(_ textView:UITextView){
if let selectedRange = textView.selectedTextRange {
let caretRect = textView.caretRect(for: selectedRange.start)
let yPos = caretRect.origin.y - (textView.frame.height/2)
let xPos = caretRect.origin.x - (textView.frame.width/2)
textView.bounds.origin = CGPoint(x: xPos, y: yPos)
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
trackCaret(textView)
return true
}
func textViewDidBeginEditing(_ textView: UITextView) {
trackCaret(textView)
}
func textViewDidEndEditing(_ textView: UITextView) {
// If you don't need to move back to the original position you can leave this out
// textView.bounds.origin = CGPoint.zero
//or if you want smooth animated scroll back then
textView.scrollRectToVisible(CGRect(x:0,
y:0,
width: textView.bounds.width,
height: textView.bounds.height),
animated: true)
}
}
有了这个你就可以得到打字机的效果而不用到处跳了。 didendEditing 方法仅用于滚动回原点 0,0。如果您不需要这样做,请将其删除。