Hello everybody this is my first question so, i'm sorry if i make some mistake.
I'm making an app that shows the content of a website. The data to be displayed is obtained by making calls to the server that returns a json with the data. This is an example of json:
{
"rubrique": {
"id_rubrique": "10",
"id_parent_rubrique": "10",
"id_secteur_rubrique": "10",
"titre_rubrique": "Rubrique title",
"texte_rubrique": "- Le rubrique est un opérateur social de premier plan, présent dans toute rubrique et principalement dans le rubrique. Il intervient sur la totalité des métiers du logement social et offre ainsi, en accompagnement des politiques urbaines et sociales des collectivités, des solutions diversifiées leur permettant de répondre aux besoins et d'accompagner les familles dans leur parcours résidentiel.\nhttp://www.website.ft/rubrique/qui-sommes-nous\n\n- {{Entités}} : \n{{[Rubrique GIE->http://website.fr/spip.php?rubrique10]}}\n\n{{[Rubrique Habitat->http://website.fr/spip.php?rubrique11]}}\n\n{{[Rubrique Promotion->http://rubrique.fr/spip.php?rubrique10]}}\n\n{{[Rubrique de l’Île-de-France->http://website.fr/spip.php?rubrique12]}}\n\n{{Rubrique Maison}} : http://www.othersite.fr/qui-sommes-nous\n\n{{[Rubrique Sarepa\n->http://website.fr/spip.php?rubrique32]}}\n\n- [Agence locales de Rubrique->http://rubrique.fr/spip.php?rubrique155]\n\n- Organisation : \n{{Directeur rubrique }} : [Patrice Patrice->http://website.fr/spip.php?rubrique6002]\n\n{{Directeur général adjoint}} : [Farid Farid->http://website.fr/spip.php?rubrique20103]\n\n{{Secrétaire général}}: [Christian Christina->http://website.fr/spip.php?rubrique201014]\n\nDélégué général à la sécurité : [Roger Roger->http://website.fr/spip.php?rubrique2018]\n\n Directeur général d'Expansiel : [Frédéric Frédéric->http://website.fr/spip.php?rubrique2006]\n\n\nGrand Paris, Développement & relations institutionnelles : [Marie Marie->http://website.fr/spip.php?rubrique429]\n\nDirectrice de la communication : Ariane Ariane\n\nDirecteur des Ressources Humaines : Philippe Philippe\n\nDirection Contrôle de gestion et Comptabilité : Bernard Bernard\n\nDirection de la Maintenance & de l’Exploitation : [Marie-Line Marie->http://website.fr/spip.php?rubrique4561]\n\nDirection des Politiques Sociales, de la Qualité et des Attributions : \n[Caroline Caroline->http://website.fr/spip.php?rubrique1963] en remplacement de [Marie-Thérèse Marie->http://website.fr/spip.php?rubrique9221]\n\nDirection de l'Action Territoriale & du Renouvellement Urbain : [Fabienne Fabienne->http://website.fr/spip.php?rubrique3127]\nDirection des Projets urbains : [Delphine Delphine->http://website.fr/spip.php?rubrique17935] \n\nAdjoints Action Territoriale : Françoise Françoise, Philippe Philippe, Alain Alain\n\n\nDirecteur Technique & du Patrimoine : [Gilles Gilles->http://website.fr/spip.php?rubrique8260]\nAdjoint : Yvon Yvon\nResponsable marchés : Jocelyne Jocelyne\nChefs de programmes : Caroline Caroline, Xavier Xavier, Mireille David\n\nDirection des Systèmes d’Information : [Olivier Olivier->http://website.fr/spip.php?rubrique23050]\n\nDirection SG Expansiel Financements - Trésorerie - Moyens généraux : \n[François-François François-François->http://website.fr/spip.php?rubrique3649]\n\nhttps://www.othersite2.fr/sites/GV/0%2C%201%2C%202%2C%203%2C%204/file.pdf\nhttp://www.othersite2.fr/qui-sommes-nous/notre-organisation-et-organigramme\n",
"contact_rubrique": "contact_rubrique",
"fonction_rubrique": "fonction",
"statut_rubrique": "publie",
"maj_rubrique": "2017-06-23 09:14:21",
"logo_rubrique": "http://website.fr/IMG/aaaaaa.png",
"permission_documenter_rubrique": "false",
"permission_instituer_rubrique": "true",
"permission_voir_rubrique": "true",
"permission_supprimer_rubrique": "false",
"permission_modifier_rubrique": "true",
"permission_iconifier_rubrique": "true",
"permission_ajouter_article_rubrique": "true",
"permission_ajouter_breve_rubrique": "false",
"permission_ajouter_rubrique_rubrique": "true"
}
}
The content of the texte_rubrique tag is shown in an UITextView and here i need to intercept when the user clicks on a link in the text. When the user clicks on the link, I do not open web browser, but I have to navigate to another view.
Now my problem is this: how can i intercept the tap on the link? I wrote some code but not works perfectly i would like. This is what i tried.
First of all i created a UITextView and add a tap reconizer
let testoRubricaView = UITextView()
let tap = UITapGestureRecognizer(target: self, action: #selector(DettaglioSingoloElementoViewController.HandleTap(sender:)))
testoRubricaView.addGestureRecognizer(tap) // add gesture recognizer to text view.
Here i tried to intercept all the link in the text, and also tried to remove the link from text and reconize the tap from the word near the link (something like a href tag of a browser):
func getAttributedString() -> NSMutableAttributedString {
let testo = rubricaCorrente.testoRubrica
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = detector.matches(in: testo, options: [], range: NSRange(location: 0, length: testo.utf16.count))
//Create a variable of the text you wish to attribute.
let textToAttribute = testo // or "This is sample text"
// Break your string in to an array, to loop through it.
let textToAttributeArray = textToAttribute.components(separatedBy: "\n")
// Define a variable as an NSMutableAttributedString() so you can append to it in your loop.
let attributedText = NSMutableAttributedString()
// Create a For - In loop that goes through each word your wish to attribute.
for word in textToAttributeArray{
// Create a pending attribution variable. Add a space for linking back together so that it doesn't looklikethis.
if(word.contains("->") && word.contains("{{[")){
let indexParolaInizio = word.range(of: "{{[")?.upperBound
let indexParolaFine = word.range(of: "->")?.lowerBound
let parolaRange = Range(uncheckedBounds: (indexParolaInizio!, indexParolaFine!))
//var parola = word.substring(to: indexParolaFine!)
var parola = word.substring(with: parolaRange)
let attributePending = NSMutableAttributedString(string: parola + "\n")
// Set an attribute on part of the string, with a length of the word.
let myRange = NSRange(location: 0, length: parola.characters.count)
// Create a custom attribute to get the value of the word tapped
let indexLinkInizio = word.range(of: "->")?.upperBound
let indexLinkFine = word.range(of: "]}}")?.lowerBound
let linkRange = Range(uncheckedBounds: (indexLinkInizio!, indexLinkFine!))
let link = word.substring(with: linkRange)
let myCustomAttribute = [ "Tapped Word:": link]
// Add the attribute to your pending attribute variable
attributePending.addAttributes(myCustomAttribute, range: myRange)
//append 'attributePending' to your attributedText variable.
attributedText.append(attributePending)
} else {
let attributePending = NSMutableAttributedString(string: word + "\n")
attributedText.append(attributePending)
}
}
return attributedText
}
And this is my tap handle
func HandleTap(sender: UITapGestureRecognizer) {
let myTextView = sender.view as! UITextView //sender is TextView
let layoutManager = myTextView.layoutManager //Set layout manager
// location of tap in myTextView coordinates
var location = sender.location(in: myTextView) //locationInView(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) //characterIndexForPoint(location, inTextContainer: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
// print the character index
print("Your character is at index: \(characterIndex)") //optional character index.
// print the character at the index
let myRange = NSRange(location: characterIndex, length: 1)
let substring = (myTextView.attributedText.string as NSString).substring(with: myRange) //substringWithRange(myRange)
print("character at index: \(substring)")
// check if the tap location has a certain attribute
let attributeName = "Tapped Word:" //make sure this matches the name in viewDidLoad()
let attributeValue = myTextView.attributedText.attribute(attributeName, at: characterIndex, effectiveRange: nil) as? String //attribute(attributeName, atIndex: characterIndex, effectiveRange: nil) as? String
if let value = attributeValue {
print("You tapped on \(attributeName) and the value is: \(value)")
}
}
}
This code not work perfectly. Some link is detected other links not but i don't know why. Can anyone help me??
If you need any other informations ask to me, thanks in advance.
Alessandro
UPDATE
After some search on stackoverflow i found this solution How do you make a UITextView detect link part in the text and still have userInteractionDisabled? i followed the answer and finally i can intercept taps on all the link. Great!! To be perfect, I should link links to keywords so that links do not appear in the text, but only keywords (like for browser href).