Comment intercepter le clic sur le lien dans UITextView?


101

Est-il possible d'effectuer une action personnalisée lorsque l'utilisateur touche le lien téléphonique détecté automatiquement dans UITextView. Veuillez ne pas utiliser UIWebView à la place.

Et s'il vous plaît, ne répétez pas simplement le texte de la référence des classes Apple - je l'ai certainement déjà lu.

Merci.

Réponses:


144

Mise à jour: De ,

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction;

De et plus tard UITextViewa la méthode déléguée:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange *NS_DEPRECATED_IOS(7_0, 10_0, "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead");*

pour intercepter les clics sur les liens. Et c'est la meilleure façon de le faire.

Pour et plus tôt, une bonne façon de le faire est de sous UIApplication-classer et d'écraser le-(BOOL)openURL:(NSURL *)url

@interface MyApplication : UIApplication {

}

@end

@implementation MyApplication


-(BOOL)openURL:(NSURL *)url{
    if  ([self.delegate openURL:url])
         return YES;
    else
         return [super openURL:url];
}
@end

Vous devrez mettre openURL:en œuvre dans votre délégué.

Maintenant, pour que l'application démarre avec votre nouvelle sous-classe de UIApplication, recherchez le fichier main.m dans votre projet. Dans ce petit fichier qui démarre votre application, il y a généralement cette ligne:

int retVal = UIApplicationMain(argc, argv, nil, nil);

Le troisième paramètre est le nom de classe de votre application. Donc, en remplaçant cette ligne pour:

int retVal = UIApplicationMain(argc, argv, @"MyApplication", nil);

Cela a fait l'affaire pour moi.


Enfin une vraie réponse! Idée simple et cool. Merci, ça marche. C'était il y a longtemps, donc je me suis déjà débrouillé sans. Peut encore aider à l'avenir. Petite correction cependant, le résultat de la branche super in else doit être retourné: return [super openURL: url];
Vladimir

2
Vous pouvez également classer UIApplicationet remplacer l'implémentation openURL. Bien que de cette façon, il soit difficile (mais pas impossible) de référencer l'implémentation d'origine.
mxcl

1
FYI - J'ai publié un BrowserViewController sur GitHub qui l'implémente pleinement, ainsi que des liens de support cliqués à partir d'un UIWebView ici: github.com/nbuggia/Browser-View-Controller--iPhone- .
Nathan Buggia

3
Cela ne semble fonctionner que pour les liens Web, pas pour les numéros de téléphone mis en forme automatiquement.
azdev

Dans quelle méthode puis-je définir le délégué de mon application?
ratsimihah

50

Sous iOS 7 ou version ultérieure

Vous pouvez utiliser la méthode de délégué UITextView suivante:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange

La vue texte appelle cette méthode si l'utilisateur appuie ou appuie longuement sur le lien URL. La mise en œuvre de cette méthode est facultative. Par défaut, la vue texte ouvre l'application chargée de gérer le type d'URL et lui transmet l'URL. Vous pouvez utiliser cette méthode pour déclencher une autre action, telle que l'affichage du contenu Web à l'URL dans une vue Web de l'application actuelle.

Important:

Les liens dans les vues de texte ne sont interactifs que si la vue de texte est sélectionnable mais non modifiable. Autrement dit, si la valeur de UITextView, la propriété sélectionnable est YES et la propriété isEditable est NO.


Je suis heureux qu'ils aient ajouté cela à UITextViewDelegate.
fsaint

Malheureusement, vous finirez toujours par utiliser UIWebViewsi vous souhaitez créer un autre texte avec le lien et non l'URL elle-même. La <a>balise reste la meilleure solution dans ce cas.
MLQ

Si d'autres personnes voient cela, vous pouvez maintenant créer un autre texte sur le lien.
Schéma

10

Pour Swift 3

textView.delegate = self

extension MyTextView: UITextViewDelegate {

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {

        GCITracking.sharedInstance.track(externalLink: URL)
        return true
    }
}

ou si la cible est> = IOS 10

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool

7

Avec Swift 5 et iOS 12, vous pouvez utiliser l'un des trois modèles suivants pour interagir avec les liens dans un fichier UITextView.


#1. Utilisation de UITextViewla dataDetectorTypespropriété.

Le moyen le plus simple d'interagir avec les numéros de téléphone, les URL ou les adresses dans un UITextViewest d'utiliser une dataDetectorTypespropriété. L'exemple de code ci-dessous montre comment l'implémenter. Avec ce code, lorsque l'utilisateur appuie sur le numéro de téléphone, un UIAlertControllermessage apparaît.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.text = "Phone number: +33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

}

# 2. Utilisation de UITextViewDelegatela textView(_:shouldInteractWith:in:interaction:)méthode de

Si vous souhaitez effectuer une action personnalisée au lieu de créer une UIAlertControllerfenêtre contextuelle lorsque vous appuyez sur un numéro de téléphone lors de l'utilisation dataDetectorTypes, vous devez vous UIViewControllerconformer au UITextViewDelegateprotocole et à l'implémenter textView(_:shouldInteractWith:in:interaction:). Le code ci-dessous montre comment l'implémenter:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.delegate = self
        textView.text = "Phone number: +33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        /* perform your own custom actions here */
        print(URL) // prints: "tel:+33687654321"

        return false // return true if you also want UIAlertController to pop up
    }

}

# 3. Utilisation NSAttributedStringetNSAttributedString.Key.link

Comme alternative, vous pouvez utiliser NSAttributedStringet définir un URLpour son NSAttributedString.Key.linkattribut. L'exemple de code ci-dessous en montre une implémentation possible. Avec ce code, lorsque l'utilisateur appuie sur la chaîne attribuée, un UIAlertControllermessage apparaît.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let attributedString = NSMutableAttributedString(string: "Contact: ")
        let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works
        let attributes = [NSAttributedString.Key.link: phoneUrl]
        let phoneAttributedString = NSAttributedString(string: "phone number", attributes: attributes)
        attributedString.append(phoneAttributedString)

        let textView = UITextView()
        textView.attributedText = attributedString
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

}

6

Version Swift:

Votre configuration UITextView standard devrait ressembler à quelque chose comme ceci, n'oubliez pas le délégué et les dataDetectorTypes.

var textView = UITextView(x: 10, y: 10, width: CardWidth - 20, height: placeholderHeight) //This is my custom initializer
textView.text = "dsfadsaf www.google.com"
textView.selectable = true
textView.dataDetectorTypes = UIDataDetectorTypes.Link
textView.delegate = self
addSubview(textView)

À la fin de votre cours, ajoutez cette pièce:

class myVC: UIViewController {
    //viewdidload and other stuff here
}

extension MainCard: UITextViewDelegate {
    func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
        //Do your stuff over here
        var webViewController = SVModalWebViewController(URL: URL)
        view.presentViewController(webViewController, animated: true, completion: nil)
        return false
    }
}

1

Swift 4:

1) Créez la classe suivante (sous-classée UITextView):

import Foundation

protocol QuickDetectLinkTextViewDelegate: class {
    func tappedLink()
}

class QuickDetectLinkTextView: UITextView {

    var linkDetectDelegate: QuickDetectLinkTextViewDelegate?

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)

    }

    required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let glyphIndex: Int? = layoutManager.glyphIndex(for: point, in: textContainer, fractionOfDistanceThroughGlyph: nil)
        let index: Int? = layoutManager.characterIndexForGlyph(at: glyphIndex ?? 0)
        if let characterIndex = index {
            if characterIndex < textStorage.length {
                if textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) != nil {
                    linkDetectDelegate?.tappedLink()
                    return self
                }
            }
        }

        return nil
    }
}


2) Partout où vous configurez votre texte, procédez comme suit:

//init, viewDidLoad, etc
textView.linkDetectDelegate = self

//outlet
@IBOutlet weak var textView: QuickDetectLinkTextView!

//change ClassName to your class
extension ClassName: QuickDetectLinkTextViewDelegate {
    func tappedLink() {
        print("Tapped link, do something")
    }
}


Si vous utilisez un storyboard, assurez-vous que votre texte ressemble à ceci dans l'inspecteur d'identité du volet droit:
entrez la description de l'image ici



Voila! Maintenant, vous obtenez le lien appuyez immédiatement au lieu de quand l'URL devrait interagir avec la méthode URL


aussi: si vous voulez que l'url ne soit pas gérée, définissez simplement la méthode shouldInteractWith pour qu'elle renvoie false
Josh O'Connor

Pensez que cela pose un tas de problèmes, comme ce qui se passe lorsque vous n'appuyez pas sur un lien. Ie je ne pense pas que la vue de texte fonctionnera plus normalement, puisque nil est retourné. La sélection change également lorsque vous appuyez sur un lien, car dans ce cas, self est renvoyé.
Drew McCormack

fonctionne très bien pour moi, vous devez gérer de tels cas pour vos besoins
Josh O'Connor

faible var linkDetectDelegate: QuickDetectLinkTextViewDelegate?
maslovsa

@vyachaslav pas pour moi, vous devez faire quelque chose de mal
Josh O'Connor

0

Je n'ai pas essayé cela moi-même, mais vous pouvez essayer d'implémenter la application:handleOpenURL:méthode dans votre délégué d'application - il semble que toutes les openURLdemandes passent par ce rappel.


0

Je ne sais pas comment vous intercepteriez la liaison de données détectée ou quel type de fonction vous devez exécuter. Mais vous pourrez peut-être utiliser la méthode didBeginEditing TextField pour exécuter un test / scan à travers le champ de texte si vous savez ce que vous recherchez ... comme comparer des chaînes de texte qui correspondent au format ### - ### - ####, ou commencez par "www." pour saisir ces champs, mais vous auriez besoin d'écrire un peu de code pour renifler la chaîne textfields, reconiser ce dont vous avez besoin, puis l'extraire pour l'utilisation de votre fonction. Je ne pense pas que ce serait si difficile, une fois que vous avez défini exactement ce que vous vouliez et que vous avez ensuite concentré vos filtres d'instruction if () sur un modèle de correspondance très spécifique de ce dont vous aviez besoin.

Bien entendu, cela implique que l'utilisateur va toucher la zone de texte pour activer didBeginEditing (). Si ce n'est pas le type d'interaction utilisateur que vous recherchiez, vous pouvez simplement utiliser un déclencheur Timer, qui démarre sur ViewDidAppear () ou autre en fonction des besoins et traverse la chaîne textfields, puis à la fin de vous exécutez la chaîne textfield méthodes que vous avez créées, il vous suffit de désactiver la minuterie.


0

application:handleOpenURL:est appelée lorsqu'une autre application ouvre votre application en ouvrant une URL avec un schéma pris en charge par votre application. Il n'est pas appelé lorsque votre application commence à ouvrir une URL.

Je pense que la seule façon de faire ce que Vladimir veut est d'utiliser un UIWebView au lieu d'un UITextView. Faites en sorte que votre contrôleur de vue implémente UIWebViewDelegate, définissez le délégué de UIWebView sur le contrôleur de vue et, dans l'implémentation du contrôleur de vue, webView:shouldStartLoadWithRequest:navigationType:pour ouvrir [request URL]dans une vue au lieu de quitter votre application et de l'ouvrir dans Mobile Safari.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.