Come intercettare il clic sul collegamento in UITextView?


101

È possibile eseguire un'azione personalizzata quando l'utente tocca il collegamento telefonico rilevato automaticamente in UITextView. Si prega di non consigliare di utilizzare invece UIWebView.

E per favore, non ripetere solo il testo dal riferimento alle classi Apple - sicuramente l'ho già letto.

Grazie.

Risposte:


144

Aggiornamento: da ,

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

A partire dal e Later UITextViewha il metodo delegato:

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

per intercettare i clic sui link. E questo è il modo migliore per farlo.

Per e prima un buon modo per farlo è creare sottoclassi UIApplicatione sovrascrivere il file-(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

Dovrai implementare openURL:nel tuo delegato.

Ora, per fare in modo che l'applicazione inizi con la tua nuova sottoclasse di UIApplication, individua il file main.m nel tuo progetto. In questo piccolo file che avvia la tua app, di solito c'è questa riga:

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

Il terzo parametro è il nome della classe per la tua applicazione. Quindi, sostituendo questa riga per:

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

Questo ha funzionato per me.


Finalmente vera risposta! Idea semplice e interessante. Grazie, funziona. È stato molto tempo fa, quindi sono già riuscito a farne a meno. Potrebbe ancora aiutare in futuro. Piccola correzione, tuttavia, dovrebbe essere restituito il risultato di super in else branch: return [super openURL: url];
Vladimir

2
Puoi anche classificare UIApplicatione sostituire l'implementazione di openURL. Sebbene in questo modo sia complicato (ma non impossibile) fare riferimento all'implementazione originale.
mxcl

1
Cordiali saluti - Ho pubblicato un BrowserViewController su GitHub che lo implementa completamente, oltre a supportare i collegamenti cliccati dall'interno di una UIWebView qui: github.com/nbuggia/Browser-View-Controller--iPhone- .
Nathan Buggia

3
Sembra funzionare solo per i collegamenti Web, non per i numeri di telefono formattati automaticamente.
azdev

In quale metodo posso impostare il delegato della mia applicazione?
ratsimihah

50

In iOS 7 o versioni successive

È possibile utilizzare il seguente metodo delegato UITextView:

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

La visualizzazione del testo chiama questo metodo se l'utente tocca o preme a lungo il collegamento URL. L'implementazione di questo metodo è opzionale. Per impostazione predefinita, la visualizzazione del testo apre l'applicazione responsabile della gestione del tipo di URL e le passa l'URL. È possibile utilizzare questo metodo per attivare un'azione alternativa, come la visualizzazione del contenuto Web all'URL in una visualizzazione Web all'interno dell'applicazione corrente.

Importante:

I collegamenti nelle viste di testo sono interattivi solo se la vista di testo è selezionabile ma non modificabile. Cioè, se il valore di UITextView la proprietà selezionabile è YES e la proprietà isEditable è NO.


Sono contento che abbiano aggiunto questo a UITextViewDelegate.
fsaint

Sfortunatamente finirai comunque per usare UIWebViewse vuoi fare del testo il link e non l'URL stesso. Il <a>tag è ancora il modo migliore in questo caso.
MLQ

Nel caso in cui altre persone lo vedano, ora puoi inserire un altro testo nel link.
Schemetrico

10

Per 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
    }
}

o se l'obiettivo è> = IOS 10

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

7

Con Swift 5 e iOS 12, puoi utilizzare uno dei tre schemi seguenti per interagire con i collegamenti in un file UITextView.


# 1. Utilizzo UITextViewdella dataDetectorTypesproprietà di.

Il modo più semplice per interagire con numeri di telefono, URL o indirizzi in a UITextViewè utilizzare dataDetectorTypesproprietà. Il codice di esempio riportato di seguito mostra come implementarlo. Con questo codice, quando l'utente tocca il numero di telefono, viene visualizzato un messaggio UIAlertController.

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. Utilizzando UITextViewDelegateil textView(_:shouldInteractWith:in:interaction:)metodo di

Se si desidera eseguire un'azione personalizzata invece di creare un UIAlertControllerpopup quando si tocca un numero di telefono durante l'utilizzo dataDetectorTypes, è necessario UIViewControllerconformarsi al UITextViewDelegateprotocollo e implementarlo textView(_:shouldInteractWith:in:interaction:). Il codice seguente mostra come implementarlo:

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. Utilizzando NSAttributedStringeNSAttributedString.Key.link

In alternativa, puoi usare NSAttributedStringe impostare un URLper il suo NSAttributedString.Key.linkattributo. Il codice di esempio sotto mostra una possibile implementazione di esso. Con questo codice, quando l'utente tocca la stringa attribuita, viene visualizzato un messaggio UIAlertController.

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

Versione rapida:

La configurazione standard di UITextView dovrebbe essere simile a questa, non dimenticare il delegato e 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)

Al termine della lezione aggiungi questo pezzo:

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) Crea la seguente classe (sottoclasse 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) Ovunque imposti la visualizzazione del testo, fai questo:

//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")
    }
}


Se stai usando lo storyboard, assicurati che la visualizzazione del testo sia simile a questa nell'Ispettore identità del riquadro destro:
inserisci qui la descrizione dell'immagine



Ecco! Ora ottieni il link tocca immediatamente invece di quando l'URL dovrebbeInteractWith metodo URL


inoltre: se si desidera che l'URL non venga gestito, è sufficiente impostare il metodo shouldInteractWith per restituire false
Josh O'Connor

Pensa che questo abbia un sacco di problemi, come quello che succede quando non tocchi un collegamento. Cioè non penso che la visualizzazione del testo funzionerà più normalmente, poiché viene restituito nil. La selezione cambierà anche quando tocchi un collegamento, perché in tal caso viene restituito self.
Drew McCormack

funziona alla grande per me, devi gestire questi casi per le tue esigenze
Josh O'Connor

debole var linkDetectDelegate: QuickDetectLinkTextViewDelegate?
maslovsa

@vyachaslav non per me, stai facendo qualcosa di sbagliato
Josh O'Connor

0

Non l'ho provato da solo, ma puoi provare a implementare il application:handleOpenURL:metodo nel delegato dell'applicazione: sembra che tutte le openURLrichieste passino attraverso questo callback.


0

Non sei sicuro di come intercetteresti il ​​collegamento dati rilevato o che tipo di funzione devi eseguire. Ma potresti essere in grado di utilizzare il metodo didBeginEditing TextField per eseguire un test / scansione attraverso il campo di testo se sai cosa stai cercando ... come confrontare le stringhe di testo che soddisfano il formato ### - ### - ####, o iniziare con "www." per afferrare quei campi, ma dovresti scrivere un piccolo codice per annusare la stringa dei campi di testo, riconciliare ciò di cui hai bisogno e quindi estrarlo per l'uso della tua funzione. Non penso che sarebbe così difficile, una volta che hai ristretto esattamente ciò che volevi e poi focalizzato i filtri dell'istruzione if () fino a un modello di corrispondenza molto specifico di ciò di cui avevi bisogno.

Ovviamente questo implica che l'utente toccherà la casella di testo per attivare didBeginEditing (). Se questo non è il tipo di interazione dell'utente che stavi cercando, potresti semplicemente usare un trigger Timer, che inizia su ViewDidAppear () o altro in base alle necessità e scorre attraverso la stringa dei campi di testo, quindi alla fine corri attraverso la stringa del campo di testo metodi che hai costruito, devi solo spegnere il timer.


0

application:handleOpenURL:viene chiamato quando un'altra app apre la tua app aprendo un URL con uno schema supportato dalla tua app. Non viene chiamato quando la tua app inizia ad aprire un URL.

Penso che l'unico modo per fare ciò che vuole Vladimir sia usare un UIWebView invece di un UITextView. Fai in modo che il controller della vista implementi UIWebViewDelegate, imposta il delegato di UIWebView sul controller della vista e nell'implementazione del controller della vista webView:shouldStartLoadWithRequest:navigationType:per aprirlo [request URL]in una vista invece di chiudere l'app e aprirla in Safari mobile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.