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)
}
Другие вопросы по тегам