Rilevamento dei tocchi sul testo attribuito con Swift
A volte per i principianti è un po 'difficile sapere come sistemare le cose (lo era comunque per me), quindi questo esempio è un po' più completo.
Aggiungi una UITextView
al tuo progetto.
Presa
Collega il UITextView
a ViewController
con una presa denominata textView
.
Attributo personalizzato
Creeremo un attributo personalizzato creando un'estensione .
Nota: questo passaggio è tecnicamente facoltativo, ma se non lo fai dovrai modificare il codice nella parte successiva per utilizzare un attributo standard come NSAttributedString.Key.foregroundColor
. Il vantaggio dell'utilizzo di un attributo personalizzato è che puoi definire i valori che desideri memorizzare nell'intervallo di testo attribuito.
Aggiungi un nuovo file swift con File> Nuovo> File ...> iOS> Sorgente> File Swift . Puoi chiamarlo come vuoi. Sto chiamando il mio NSAttributedStringKey + CustomAttribute.swift .
Incolla il codice seguente:
import Foundation
extension NSAttributedString.Key {
static let myAttributeName = NSAttributedString.Key(rawValue: "MyCustomAttribute")
}
Codice
Sostituisci il codice in ViewController.swift con il seguente. Nota il 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)")
}
}
}
}
Ora se tocchi la "w" di "Swift", dovresti ottenere il seguente risultato:
character index: 1
character at index: w
You tapped on MyCustomAttribute and the value is: some value
Appunti
- Qui ho usato un attributo personalizzato, ma avrebbe potuto essere altrettanto facilmente
NSAttributedString.Key.foregroundColor
(colore del testo) che ha un valore di UIColor.green
.
- In precedenza la visualizzazione del testo non poteva essere modificabile o selezionabile, ma nella mia risposta aggiornata per Swift 4.2 sembra funzionare bene, indipendentemente dal fatto che siano selezionati o meno.
Ulteriore studio
Questa risposta era basata su molte altre risposte a questa domanda. Oltre a questi, vedi anche