UITextInput.characterRange(at:) 偏移了几个像素
UITextInput.characterRange(at:) is off by a few pixels
在我的 UITextView
子类中添加点击识别器后,我试图获取正在点击的字符:
var textRecognizer: UITapGestureRecognizer!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
textContainer.lineFragmentPadding = 0
textContainerInset = .zero
textRecognizer = UITapGestureRecognizer(target: self, action: #selector(textTapped))
textRecognizer.numberOfTapsRequired = 1
addGestureRecognizer(textRecognizer)
}
@objc func textTapped(recognizer: UITapGestureRecognizer) {
let location = recognizer.location(in: self)
if let cRange = characterRange(at: location) {
let cPosition = offset(from: beginningOfDocument, to: cRange.start)
let cChar = text[Range(NSRange(location: cPosition, length: 1), in: text)!]
print(cChar)
}
}
问题是,如果我的 attributedText 是 "Hello world\nWelcome to Stack Overflow"
并且我点击字母的左侧部分,例如字母 f
的左侧,那么 characterRange(at: location)
returns 前一个字母 r
而不是返回 f
.
在我看来,characterRange(at:)
有问题:
- 如果你在索引
n
字符的左半部分给它一个点,它 returns 范围 (n-1, n)
- 如果你在索引
n
字符的右半部分给它一个点,它 returns 范围 (n, n+1)
- 如果你在索引
beginningOfDocument
字符的左半部分给它一个点,它 returns nil
- 如果你在索引
endOfDocument
字符的右半部分给它一个点,它 returns (endOfDocument, endOfDocument+1)
textInput 两端行为的差异表明某处存在错误。
它的行为类似于一种“光标位置在点”函数,这使得确定此时实际是哪个字符变得不可靠:is it光标前的字符还是光标后的字符?
closestPosition(to:)
遇到完全相同的问题。
一个可行的替代方案是 layoutManager.characterIndex(for:in:fractionOfDistanceBetweenInsertionPoints:)
. Credit to vacawama:
@objc func textTapped(recognizer: UITapGestureRecognizer) {
var location = recognizer.location(in: self)
location.x -= textContainerInset.left
location.y -= textContainerInset.top
let cPosition = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
let cChar = text[Range(NSRange(location: cPosition, length: 1), in: text)!]
print(cChar)
}
在我的 UITextView
子类中添加点击识别器后,我试图获取正在点击的字符:
var textRecognizer: UITapGestureRecognizer!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
textContainer.lineFragmentPadding = 0
textContainerInset = .zero
textRecognizer = UITapGestureRecognizer(target: self, action: #selector(textTapped))
textRecognizer.numberOfTapsRequired = 1
addGestureRecognizer(textRecognizer)
}
@objc func textTapped(recognizer: UITapGestureRecognizer) {
let location = recognizer.location(in: self)
if let cRange = characterRange(at: location) {
let cPosition = offset(from: beginningOfDocument, to: cRange.start)
let cChar = text[Range(NSRange(location: cPosition, length: 1), in: text)!]
print(cChar)
}
}
问题是,如果我的 attributedText 是 "Hello world\nWelcome to Stack Overflow"
并且我点击字母的左侧部分,例如字母 f
的左侧,那么 characterRange(at: location)
returns 前一个字母 r
而不是返回 f
.
在我看来,characterRange(at:)
有问题:
- 如果你在索引
n
字符的左半部分给它一个点,它 returns 范围(n-1, n)
- 如果你在索引
n
字符的右半部分给它一个点,它 returns 范围(n, n+1)
- 如果你在索引
beginningOfDocument
字符的左半部分给它一个点,它 returnsnil
- 如果你在索引
endOfDocument
字符的右半部分给它一个点,它 returns(endOfDocument, endOfDocument+1)
textInput 两端行为的差异表明某处存在错误。
它的行为类似于一种“光标位置在点”函数,这使得确定此时实际是哪个字符变得不可靠:is it光标前的字符还是光标后的字符?
closestPosition(to:)
遇到完全相同的问题。
一个可行的替代方案是 layoutManager.characterIndex(for:in:fractionOfDistanceBetweenInsertionPoints:)
. Credit to vacawama:
@objc func textTapped(recognizer: UITapGestureRecognizer) {
var location = recognizer.location(in: self)
location.x -= textContainerInset.left
location.y -= textContainerInset.top
let cPosition = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
let cChar = text[Range(NSRange(location: cPosition, length: 1), in: text)!]
print(cChar)
}