Wie kann man einen Klick-Link in UITextView abfangen?

101

Ist es möglich, benutzerdefinierte Aktionen auszuführen, wenn der Benutzer die automatisch erkannte Telefonverbindung in UITextView berührt? Bitte raten Sie nicht, stattdessen UIWebView zu verwenden.

Und bitte wiederholen Sie nicht nur den Text aus der Referenz für Apfelklassen - sicherlich habe ich ihn bereits gelesen.

Vielen Dank.

Vladimir
quelle

Antworten:

144

Update: Von ,

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

Von und später UITextViewhat die Delegatenmethode:

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

um die Klicks auf Links abzufangen. Und das ist der beste Weg, es zu tun.

Zum und früher ist es eine gute Möglichkeit, dies zu tun, indem Sie das unterordnen UIApplicationund überschreiben-(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

Sie müssen openURL:in Ihrem Delegaten implementieren .

UIApplicationUm die Anwendung mit Ihrer neuen Unterklasse von zu starten , suchen Sie die Datei main.m in Ihrem Projekt. In dieser kleinen Datei, die Ihre App bootet, befindet sich normalerweise die folgende Zeile:

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

Der dritte Parameter ist der Klassenname für Ihre Anwendung. Ersetzen Sie diese Zeile durch:

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

Das hat den Trick für mich getan.

fsaint
quelle
Endlich echte Antwort! Einfache und coole Idee. Danke, es funktioniert. Es ist lange her, also habe ich es schon ohne geschafft. Kann in Zukunft noch helfen. Eine kleine Korrektur, die aus dem Zweig super in else resultiert, sollte zurückgegeben werden: return [super openURL: url];
Vladimir
2
Sie können UIApplicationdie openURL-Implementierung auch kategorisieren und ersetzen. Auf diese Weise ist es schwierig (aber nicht unmöglich), auf die ursprüngliche Implementierung zu verweisen.
mxcl
1
Zu Ihrer Information - Ich habe einen BrowserViewController auf GitHub veröffentlicht, der dies vollständig implementiert, sowie Links, die in einer UIWebView hier angeklickt werden: github.com/nbuggia/Browser-View-Controller--iPhone- .
Nathan Buggia
3
Dies scheint nur für Weblinks zu funktionieren, nicht für automatisch formatierte Telefonnummern.
Azdev
Auf welche Weise kann ich den Delegaten meiner Anwendung festlegen?
Ratsimihah
50

In iOS 7 oder höher

Sie können die folgende UITextView-Delegatenmethode verwenden:

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

Die Textansicht ruft diese Methode auf, wenn der Benutzer auf den URL-Link tippt oder ihn lange drückt. Die Implementierung dieser Methode ist optional. Standardmäßig öffnet die Textansicht die Anwendung, die für die Verarbeitung des URL-Typs verantwortlich ist, und übergibt ihr die URL. Mit dieser Methode können Sie eine alternative Aktion auslösen, z. B. das Anzeigen des Webinhalts unter der URL in einer Webansicht in der aktuellen Anwendung.

Wichtig:

Links in Textansichten sind nur dann interaktiv, wenn die Textansicht auswählbar, aber nicht bearbeitbar ist. Das heißt, wenn der Wert von UITextView die auswählbare Eigenschaft YES und die isEditable-Eigenschaft NO ist.

Rajan Balana
quelle
Ich bin froh, dass sie dies dem UITextViewDelegate hinzugefügt haben.
Heiliger
Leider werden Sie immer noch verwenden, UIWebViewwenn Sie einen anderen Text als Link und nicht als URL selbst verwenden möchten . Das <a>Tag ist in diesem Fall immer noch der beste Weg.
Matthew Quiros
Falls andere Leute dies sehen, können Sie jetzt einen anderen Text zum Link machen.
Schema
10

Für 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
    }
}

oder wenn das Ziel> = IOS 10 ist

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

Schnelle Version:

Ihr Standard-UITextView-Setup sollte ungefähr so ​​aussehen. Vergessen Sie nicht den Delegaten und die 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)

Fügen Sie nach dem Ende Ihres Unterrichts dieses Stück hinzu:

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
    }
}
Esqarrouth
quelle
6

Mit Swift 5 und iOS 12 können Sie eines der drei folgenden Muster verwenden, um mit Links in a zu interagieren UITextView.


# 1. Verwenden UITextViewder dataDetectorTypesEigenschaft von.

Der einfachste Weg, mit Telefonnummern, URLs oder Adressen in einem zu interagieren, UITextViewist die Verwendung von dataDetectorTypesEigenschaften. Der folgende Beispielcode zeigt, wie er implementiert wird. Wenn der Benutzer mit diesem Code auf die Telefonnummer tippt, wird ein UIAlertControllerangezeigt.

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. Mit UITextViewDelegateder textView(_:shouldInteractWith:in:interaction:)Methode von

Wenn Sie eine benutzerdefinierte Aktion ausführen möchten, anstatt ein UIAlertControllerPopup zu erstellen, wenn Sie während der Verwendung auf eine Telefonnummer tippen dataDetectorTypes, müssen Sie UIViewControllerdas UITextViewDelegateProtokoll anpassen und implementieren textView(_:shouldInteractWith:in:interaction:). Der folgende Code zeigt, wie es implementiert wird:

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. Verwenden von NSAttributedStringundNSAttributedString.Key.link

Als Alternative können Sie mit NSAttributedStringein und setzen URLfür sein NSAttributedString.Key.linkAttribut folgenden Beispielcode zeigt eine mögliche Implementierung davon. Wenn der Benutzer mit diesem Code auf die zugewiesene Zeichenfolge tippt, wird ein UIAlertControllerPopup angezeigt.

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
    }

}
Imanou Petit
quelle
1

Swift 4:

1) Erstellen Sie die folgende Klasse (UITextView mit Unterklasse):

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) Tun Sie Folgendes, wo immer Sie Ihre Textansicht einrichten:

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


Wenn Sie ein Storyboard verwenden, stellen Sie sicher, dass Ihre Textansicht im Identitätsinspektor des rechten Bereichs wie folgt aussieht:
Geben Sie hier die Bildbeschreibung ein



Voila! Jetzt erhalten Sie den Link sofort tippen anstatt wann die URL sollte mit der URL-Methode interagieren

Josh O'Connor
quelle
außerdem: Wenn Sie möchten, dass die URL nicht verarbeitet wird, setzen Sie einfach die shouldInteractWith-Methode so, dass sie false zurückgibt
Josh O'Connor
Denken Sie, dies hat eine Reihe von Problemen, z. B. was passiert, wenn Sie nicht auf einen Link tippen. Dh ich glaube nicht, dass die Textansicht mehr normal funktioniert, da nil zurückgegeben wird. Die Auswahl ändert sich auch, wenn Sie auf einen Link tippen, da in diesem Fall self zurückgegeben wird.
Drew McCormack
funktioniert gut für mich, Sie müssen solche Fälle für Ihre Bedürfnisse behandeln
Josh O'Connor
schwach var linkDetectDelegate: QuickDetectLinkTextViewDelegate?
Maslovsa
@vyachaslav nicht für mich, Sie müssen etwas falsch machen
Josh O'Connor
0

Ich habe das selbst nicht versucht, aber Sie können versuchen, die application:handleOpenURL:Methode in Ihrem Anwendungsdelegierten zu implementieren. Es sieht so aus, als würden alle openURLAnforderungen diesen Rückruf durchlaufen.

Vladimir
quelle
0

Sie sind sich nicht sicher, wie Sie die erkannte Datenverbindung abfangen würden oder welche Art von Funktion Sie ausführen müssen. Möglicherweise können Sie jedoch die didBeginEditing TextField-Methode verwenden, um einen Test / Scan durch das Textfeld auszuführen, wenn Sie wissen, wonach Sie suchen. So können Sie beispielsweise Textzeichenfolgen vergleichen, die dem Format ### - ### - #### entsprechen. oder beginnen Sie mit "www". Um diese Felder zu erfassen, müssten Sie jedoch einen kleinen Code schreiben, um die Zeichenfolge der Textfelder zu durchsuchen, das zu rekonstruieren, was Sie benötigen, und es dann für die Verwendung durch Ihre Funktion zu extrahieren. Ich denke nicht, dass dies so schwierig wäre, wenn Sie genau eingegrenzt haben, was Sie wollten, und dann Ihre if () -Anweisungsfilter auf ein ganz bestimmtes Übereinstimmungsmuster von dem konzentriert haben, was Sie brauchten.

Dies bedeutet natürlich, dass der Benutzer das Textfeld berühren wird, um didBeginEditing () zu aktivieren. Wenn dies nicht die Art von Benutzerinteraktion ist, nach der Sie gesucht haben, können Sie einfach einen Trigger-Timer verwenden, der je nach Bedarf auf ViewDidAppear () oder einem anderen Programm startet und die Textfeldzeichenfolge durchläuft. Am Ende durchlaufen Sie die Textfeldzeichenfolge Methoden, die Sie erstellt haben, schalten Sie einfach den Timer wieder aus.

Newbyman
quelle
0

application:handleOpenURL:wird aufgerufen, wenn eine andere App Ihre App öffnet, indem Sie eine URL mit einem von Ihrer App unterstützten Schema öffnen. Es wird nicht aufgerufen, wenn Ihre App eine URL öffnet.

Ich denke, der einzige Weg, um das zu tun, was Vladimir will, ist die Verwendung eines UIWebView anstelle eines UITextView. Lassen Sie Ihren View Controller UIWebViewDelegate implementieren, setzen Sie den UIWebView-Delegaten auf den View Controller und webView:shouldStartLoadWithRequest:navigationType:öffnen Sie [request URL]im View Controller-Implementieren eine Ansicht, anstatt Ihre App zu beenden und in Mobile Safari zu öffnen .

A. Jesse Jiryu Davis
quelle