UITextInput.characterRange(at:) отключен на несколько пикселей
После добавления распознавателя крана в мой 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)
}
}
Проблема в том, что если мой атрибут "Hello world\nWelcome to Stack Overflow"
и я нажимаю на левую часть письма, как левая сторона письма f
, затем characterRange(at: location)
возвращает предыдущее письмо r
вместо возвращения f
,
1 ответ
С моей точки зрения, characterRange(at:)
глючит:
- Если вы дадите ему точку в левой половине символа в индексе
n
, он возвращает диапазон(n-1, n)
- Если вы дадите ему точку на правой половине символа в индексе
n
, он возвращает диапазон(n, n+1)
- Если вы дадите ему точку в левой половине символа в индексе
beginningOfDocument
, это возвращаетnil
- Если вы дадите ему точку на правой половине символа в индексе
endOfDocument
, это возвращает(endOfDocument, endOfDocument+1)
Расхождение в поведении на концах textInput демонстрирует, что где-то есть ошибка.
Он ведет себя как своего рода функция " позиция курсора в точке ", что делает ненадежным определение того, какой символ на самом деле находится в этой точке: символ перед курсором или символ после курсора?
closestPosition(to:)
страдает от точно такой же проблемы.
Рабочая альтернатива layoutManager.characterIndex(for:in:fractionOfDistanceBetweenInsertionPoints:)
, Кредит на 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)
}