Détecter les tapotements sur le texte attribué avec Swift
Parfois, pour les débutants, il est un peu difficile de savoir comment mettre en place les choses (c'était pour moi en tout cas), donc cet exemple est un peu plus complet.
Ajoutez un UITextView
à votre projet.
Sortie
Connectez le UITextView
au ViewController
avec une prise nommée textView
.
Attribut personnalisé
Nous allons créer un attribut personnalisé en créant une extension .
Remarque: Cette étape est techniquement facultative, mais si vous ne le faites pas, vous devrez éditer le code dans la partie suivante pour utiliser un attribut standard comme NSAttributedString.Key.foregroundColor
. L'avantage de l'utilisation d'un attribut personnalisé est que vous pouvez définir les valeurs que vous souhaitez stocker dans la plage de texte attribuée.
Ajoutez un nouveau fichier Swift avec Fichier> Nouveau> Fichier ...> iOS> Source> Fichier Swift . Vous pouvez l'appeler comme vous le souhaitez. J'appelle le mien NSAttributedStringKey + CustomAttribute.swift .
Collez le code suivant:
import Foundation
extension NSAttributedString.Key {
static let myAttributeName = NSAttributedString.Key(rawValue: "MyCustomAttribute")
}
Code
Remplacez le code dans ViewController.swift par ce qui suit. Notez le 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)")
}
}
}
}
Maintenant, si vous appuyez sur le "w" de "Swift", vous devriez obtenir le résultat suivant:
character index: 1
character at index: w
You tapped on MyCustomAttribute and the value is: some value
Remarques
- Ici, j'ai utilisé un attribut personnalisé, mais il aurait tout aussi bien pu être
NSAttributedString.Key.foregroundColor
(couleur du texte) qui a une valeur de UIColor.green
.
- Auparavant, la vue texte ne pouvait pas être modifiable ou sélectionnable, mais dans ma réponse mise à jour pour Swift 4.2, elle semble fonctionner correctement, qu'elles soient sélectionnées ou non.
Une étude plus approfondie
Cette réponse était basée sur plusieurs autres réponses à cette question. Outre ceux-ci, voir aussi