web-dev-qa-db-fra.com

Comment intercepter, cliquez sur le lien dans UITextView?

Est-il possible d'effectuer une action personnalisée lorsque l'utilisateur touche un lien téléphonique auto-détecté dans UITextView. Ne conseillez pas d'utiliser plutôt UIWebView. 

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

Merci.

87
Vladimir

Mise à jour: De ios10

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

De ios7 et Ultérieur UITextView a 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 ios6 et les versions antérieures, une bonne manière de procéder consiste à sous-classer UIApplication et à écraser la -(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 implémenter openURL: dans votre délégué. 

Maintenant, pour que l'application démarre avec votre nouvelle sous-classe de UIApplication, localisez le fichier main.m dans votre projet. Dans ce petit fichier qui initialise 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 la classe pour votre application. Donc, remplacer cette ligne pour:

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

Cela a fait le tour pour moi.

129
fsaint

Dans 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 de manière prolongée sur le lien URL. L'implémentation 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 action alternative, telle que l'affichage du contenu Web à l'URL dans un affichage Web de l'application en cours.

Important:  

Les liens dans les vues texte ne sont interactifs que si la vue texte est sélectionnable mais non éditable. C'est-à-dire si la valeur de UITextView la propriété sélectionnable est YES et la propriété isEditable est NO.

50
Rajan Balana

Version rapide:

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

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)

Après la fin de votre classe, 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
    }
}
4
Esqarrouth

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
4
Ryan Heitner

Avec Swift 3 et i0S 10, le moyen le plus simple d’interagir avec des numéros de téléphone, des URL ou des adresses dans UITextView est d’utiliser UIDataDetectorTypes . Le code ci-dessous montre comment afficher un numéro de téléphone dans une UITextView afin que l'utilisateur puisse interagir avec ce numéro.

import UIKit

class ViewController: UIViewController {

    // Link this outlet to a UITextView in your Storyboard
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.text = "+33687654321"
        textView.isUserInteractionEnabled = true // default: true
        textView.isEditable = false // default: true
        textView.isSelectable = true // default: true
        textView.dataDetectorTypes = [.phoneNumber]
    }

}

Avec ce code, lorsque vous cliquez sur le numéro de téléphone, une UIAlertController apparaîtra.


Vous pouvez également utiliser NSAttributedString :

import UIKit

class ViewController: UIViewController {

    // Link this outlet to a UITextView in your Storyboard
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works
        let attributes = [NSLinkAttributeName: phoneUrl]
        let attributedString = NSAttributedString(string: "phone number", attributes: attributes)

        textView.attributedText = attributedString
        textView.isUserInteractionEnabled = true // default: true
        textView.isEditable = false // default: true
        textView.isSelectable = true // default: true
    }

}

Avec ce code, lorsque vous cliquez sur la chaîne attribuée, une UIAlertController apparaîtra.


Toutefois, vous souhaiterez peut-être effectuer une action personnalisée au lieu de faire apparaître une UIAlertController lorsque vous cliquez sur un numéro de téléphone. Vous pouvez également garder une variable UIAlertController pour qu'elle apparaisse et exécute votre propre action personnalisée dans le même temps.

Dans les deux cas, vous devrez rendre votre UIViewController conforme au protocole UITextViewDelegate et implémenter textView(_:shouldInteractWith:in:interaction:) . Le code ci-dessous montre comment faire.

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    // Link this outlet to a UITextView in your Storyboard
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.delegate = self

        textView.text = "+33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
    }

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

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

}

Avec ce code, lorsque vous cliquez sur le numéro de téléphone, aucune UIAlertController n'apparaîtra et vous obtiendrez l'impression suivante dans votre console:

tel: +33687654321

2
Imanou Petit

J'ai un contenu dynamique en mode texte, qui peut contenir un lien. ShouldInteractWithURL est appelé uniquement lorsque l'utilisateur appuie longuement sur le lien mais n'appelle pas au robinet S'il vous plaît rediriger si un ami a une référence à elle.

Voici quelques extraits du code.

UITextView *ltextView = [[UITextView alloc] init];
[ltextView setScrollEnabled:YES];
[ltextView setDataDetectorTypes:UIDataDetectorTypeLink];
ltextView.selectable = YES;
[ltextView setEditable:NO];
ltextView.userInteractionEnabled = YES;
ltextView.delegate = (id)self;
ltextView.delaysContentTouches = NO;
[self.view addsubview:ltextview];

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

    [self.mActionDelegate userClickedOnImageLinkFromWebview:URL];

    NSLog(@"urls is :- %@",URL);
    return FALSE;
}

La méthode déléguée ci-dessus n'est pas appelée au robinet.

Cordialement, Rohit Jankar

1
Rohit

application:handleOpenURL: est appelé lorsqu'une autre application ouvre votre -app application en ouvrant une URL avec un modèle que votre application prend en charge. 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. Amenez votre contrôleur de vue à implémenter UIWebViewDelegate, définissez le délégué de UIWebView sur le contrôleur de vue, puis implémentez webView:shouldStartLoadWithRequest:navigationType: dans le contrôleur de vue pour ouvrir [request URL] au lieu de quitter votre application et de l'ouvrir dans Mobile Safari.

0

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

0
Vladimir

Vous ne savez pas comment vous allez intercepter la liaison de données détectée, ni quel type de fonction vous devez exécuter. Mais vous pourrez peut-être utiliser la méthode textField didBeginEditing pour exécuter un test/une analyse du champ de texte si vous savez ce que vous cherchez. ou commencez par "www." pour saisir ces champs, mais vous auriez besoin d'écrire un petit code pour scruter la chaîne de champs de texte, reconstituer 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 précisé exactement ce que vous vouliez, puis que votre instruction if () a été filtrée selon 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 afin d'activer didBeginEditing (). Si ce n'est pas le type d'interaction utilisateur que vous recherchez, vous pouvez simplement utiliser un minuteur de déclenchement, qui commence par ViewDidAppear () ou un autre système en fonction des besoins, puis parcourt la chaîne de champs de texte, puis la fin méthodes que vous avez construites, il vous suffit de désactiver le minuteur. 

0
Newbyman

Swift 4:

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

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) Où que vous configuriez votre textview, 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 le storyboard, assurez-vous que la vue texte ressemble à ceci dans l'inspecteur d'identité du volet de droite:
 enter image description here



Voilà! Maintenant, vous obtenez le lien appuyez immédiatement après le lien au lieu de l'URL shouldInteractWith, méthode d'URL

0
Josh O'Connor