Detectando toques no texto atribuído com o Swift
Às vezes, para iniciantes, é um pouco difícil saber como configurar as coisas (foi mesmo para mim), então esse exemplo é um pouco mais completo.
Adicione um UITextView
ao seu projeto.
Saída
Conecte UITextView
ao ViewController
com uma tomada chamada textView
.
Atributo personalizado
Vamos criar um atributo personalizado criando uma extensão .
Nota: Esta etapa é tecnicamente opcional, mas se você não fizer isso, precisará editar o código na próxima parte para usar um atributo padrão como NSAttributedString.Key.foregroundColor
. A vantagem de usar um atributo customizado é que você pode definir quais valores deseja armazenar no intervalo de texto atribuído.
Adicione um novo arquivo rápido com Arquivo> Novo> Arquivo ...> iOS> Origem> Arquivo Swift . Você pode chamá-lo como quiser. Estou chamando o meu NSAttributedStringKey + CustomAttribute.swift .
Cole o seguinte código:
import Foundation
extension NSAttributedString.Key {
static let myAttributeName = NSAttributedString.Key(rawValue: "MyCustomAttribute")
}
Código
Substitua o código em ViewController.swift pelo seguinte. Observe o UIGestureRecognizerDelegate
.
import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Create an attributed string
let myString = NSMutableAttributedString(string: "Swift attributed text")
// Set an attribute on part of the string
let myRange = NSRange(location: 0, length: 5) // range of "Swift"
let myCustomAttribute = [ NSAttributedString.Key.myAttributeName: "some value"]
myString.addAttributes(myCustomAttribute, range: myRange)
textView.attributedText = myString
// Add tap gesture recognizer to Text View
let tap = UITapGestureRecognizer(target: self, action: #selector(myMethodToHandleTap(_:)))
tap.delegate = self
textView.addGestureRecognizer(tap)
}
@objc func myMethodToHandleTap(_ sender: UITapGestureRecognizer) {
let myTextView = sender.view as! UITextView
let layoutManager = myTextView.layoutManager
// location of tap in myTextView coordinates and taking the inset into account
var location = sender.location(in: myTextView)
location.x -= myTextView.textContainerInset.left;
location.y -= myTextView.textContainerInset.top;
// character index at tap location
let characterIndex = layoutManager.characterIndex(for: location, in: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
// print the character index
print("character index: \(characterIndex)")
// print the character at the index
let myRange = NSRange(location: characterIndex, length: 1)
let substring = (myTextView.attributedText.string as NSString).substring(with: myRange)
print("character at index: \(substring)")
// check if the tap location has a certain attribute
let attributeName = NSAttributedString.Key.myAttributeName
let attributeValue = myTextView.attributedText?.attribute(attributeName, at: characterIndex, effectiveRange: nil)
if let value = attributeValue {
print("You tapped on \(attributeName.rawValue) and the value is: \(value)")
}
}
}
}
Agora, se você tocar no "w" de "Swift", deverá obter o seguinte resultado:
character index: 1
character at index: w
You tapped on MyCustomAttribute and the value is: some value
Notas
- Aqui eu usei um atributo personalizado, mas poderia ter sido tão facilmente
NSAttributedString.Key.foregroundColor
(cor do texto) que tem um valor de UIColor.green
.
- Antigamente, a exibição de texto não podia ser editável ou selecionável, mas, na minha resposta atualizada para o Swift 4.2, parece estar funcionando bem, independentemente de eles estarem selecionados ou não.
Um estudo mais aprofundado
Esta resposta foi baseada em várias outras respostas para esta pergunta. Além destes, veja também