Wie kann ich einen anklickbaren Link in einem NSAttributedString erstellen?


200

Es ist trivial, Hyperlinks in a anklickbar zu machen UITextView. Sie haben einfach das Kontrollkästchen "Links erkennen" in der Ansicht in IB aktiviert. Es erkennt HTTP-Links und wandelt sie in Hyperlinks um.

Dies bedeutet jedoch immer noch, dass der Benutzer den "rohen" Link sieht. Mit RTF-Dateien und HTML können Sie eine vom Benutzer lesbare Zeichenfolge mit einem Link "dahinter" einrichten.

Es ist einfach, zugeordneten Text in eine Textansicht (oder ein UILabeloder) zu installieren UITextField. Wenn dieser zugeordnete Text jedoch einen Link enthält, kann er nicht angeklickt werden.

Gibt es eine Möglichkeit der Benutzer lesbaren Text anklickbar in einem zu machen UITextView, UILabeloder UITextField?

Das Markup ist bei SO anders, aber hier ist die allgemeine Idee. Was ich will, ist Text wie folgt:

Dieser Morph wurde mit Face Dancer erstellt . Klicken Sie hier, um ihn im App Store anzuzeigen.

Das einzige was ich bekommen kann ist folgendes:

Dieser Morph wurde mit Face Dancer erstellt. Klicken Sie auf http://example.com/facedancer , um ihn im App Store anzuzeigen.


Versuchen Sie dieses Beispiel .. IFTweetLabel Hoffe, es hilft ..
Vidhyanand


Gute Arbeit, die im Handumdrehen über 100 km hinausgeht. Willkommen im 100K Club. Wohlverdient!
Vacawama

@vacawama, warte, wann ist das passiert? Ich war bei 98k, als ich das letzte Mal nachgesehen habe! (Ich höre Gerüchte, dass Sie als Mitglied des 100k Clubs SO Beute bekommen?)
Duncan C

Sie haben die Upvotes für Fragen von +5 auf +10 geändert. Wenn Sie also 800 Upvotes hätten, würden Sie blitzschnell +4000 erhalten. Ich warte immer noch auf 100.000 Beute (gekreuzt im April). Etwas über den Wechsel der Swag-Anbieter ...
Vacawama

Antworten:


156

Verwenden Sie NSMutableAttributedString .

NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:@"Google"];
[str addAttribute: NSLinkAttributeName value: @"http://www.google.com" range: NSMakeRange(0, str.length)];
yourTextView.attributedText = str;

Bearbeiten :

Hier geht es nicht direkt um die Frage, sondern nur zur Verdeutlichung, UITextFieldund UILabeldas Öffnen von URLs wird nicht unterstützt. Wenn Sie UILabelmit Links verwenden möchten, können Sie TTTAttributedLabel überprüfen .

Auch sollten Sie festlegen dataDetectorTypesWert Ihrer UITextViewan UIDataDetectorTypeLinkoder UIDataDetectorTypeAllauf URLs öffnen , wenn darauf geklickt. Oder Sie können die Delegatmethode verwenden, wie in den Kommentaren vorgeschlagen.


7
Ja, es funktioniert, fügen Sie es einfach in eine UITextView ein und überschreiben Sie die Delegatenmethode: - (BOOL) textView: (UITextView *) textView shouldInteractWithURL: (NSURL *) url inRange: (NSRange) characterRange
Yunus Nedim Mehel

Dies funktioniert in einem UILabel nicht - nichts passiert, wenn Sie auf das Feld tippen.
Jack BeNimble

7
@saboehnke meinst du eine Methode aufrufen, wenn auf den Link geklickt wird? Wenn ja, implementieren Sie die Delegate-Methode, geben Sie eine Dummy-URL als Attribut an und rufen Sie Ihre Methode in- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
ujell

2
Ich weiß nicht, wie es funktioniert. Der Wert des Attributs sollte vom Typ sein NSURL. ----[str addAttribute: NSLinkAttributeName value: [NSURL URLWithString:@"http://www.google.com"] range: NSMakeRange(0, str.length)];
Nirav Dangi

1
@ NiravDangi vonNSAttributedString.h UIKIT_EXTERN NSString * const NSLinkAttributeName NS_AVAILABLE(10_0, 7_0); // NSURL (preferred) or NSString
Ahmed Nawar

142

Ich fand das wirklich nützlich, aber ich musste es an einigen Stellen tun, also habe ich meinen Ansatz in einer einfachen Erweiterung zusammengefasst, um NSMutableAttributedString:

Swift 3

extension NSMutableAttributedString {

    public func setAsLink(textToFind:String, linkURL:String) -> Bool {

        let foundRange = self.mutableString.range(of: textToFind)
        if foundRange.location != NSNotFound {
            self.addAttribute(.link, value: linkURL, range: foundRange)
            return true
        }
        return false
    }
}

Swift 2

import Foundation

extension NSMutableAttributedString {

   public func setAsLink(textToFind:String, linkURL:String) -> Bool {

       let foundRange = self.mutableString.rangeOfString(textToFind)
       if foundRange.location != NSNotFound {
           self.addAttribute(NSLinkAttributeName, value: linkURL, range: foundRange)
           return true
       }
       return false
   }
}

Anwendungsbeispiel:

let attributedString = NSMutableAttributedString(string:"I love stackoverflow!")
let linkWasSet = attributedString.setAsLink("stackoverflow", linkURL: "http://stackoverflow.com")

if linkWasSet {
    // adjust more attributedString properties
}

Ziel c

Ich habe gerade die Anforderung erfüllt, dasselbe in einem reinen Objective-C-Projekt zu tun. Hier ist also die Objective-C-Kategorie.

@interface NSMutableAttributedString (SetAsLinkSupport)

- (BOOL)setAsLink:(NSString*)textToFind linkURL:(NSString*)linkURL;

@end


@implementation NSMutableAttributedString (SetAsLinkSupport)

- (BOOL)setAsLink:(NSString*)textToFind linkURL:(NSString*)linkURL {

     NSRange foundRange = [self.mutableString rangeOfString:textToFind];
     if (foundRange.location != NSNotFound) {
         [self addAttribute:NSLinkAttributeName value:linkURL range:foundRange];
         return YES;
     }
     return NO;
}

@end

Anwendungsbeispiel:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:"I love stackoverflow!"];

BOOL linkWasSet = [attributedString setAsLink:@"stackoverflow" linkURL:@"http://stackoverflow.com"];

if (linkWasSet) {
    // adjust more attributedString properties
}

Stellen Sie sicher, dass das Verhaltensattribut von NSTextField als auswählbar festgelegt ist. Verhaltensattribut Xcode NSTextField


Ein schnelles Anwendungsbeispiel hierfür wäre sehr dankbar.
Ioopl

3
@ioop. Ich habe dem ursprünglichen Beitrag oben ein sehr kleines Beispiel hinzugefügt, hoffe, das hilft.
Karl Nosworthy

7
Das hat richtig funktioniert. Ich möchte nur sagen, dass Sie Ihre UITextView auswählbar machen müssen, damit der Link anklickbar ist
lujop

1
@felecia genet, sowohl in der Objective C- als auch in der Swift-Implementierung gibt die Methode ein boolesches Ergebnis zurück, um anzuzeigen, ob eine Übereinstimmung und eine resultierende Menge stattgefunden haben. Der Fehler, den Sie sehen, ist, dass Sie dieses Ergebnis nicht erfassen - was in Ordnung ist. Sie können dieses Ergebnis entweder erfassen, indem Sie es einer lokalen Variablen zuweisen, oder die Methode anpassen, um zu verhindern, dass der boolesche Wert zurückgegeben wird, wenn dies Ihren Anforderungen besser entspricht. Ich hoffe das hilft?
Karl Nosworthy

1
Kein Problem @feleciagenet, ich habe das Speichern und Überprüfen des Methodenergebnisses sowohl zu den Swift- als auch zu den ObjectiveC-Beispielen hinzugefügt.
Karl Nosworthy

34

Ich habe gerade eine Unterklasse von UILabel erstellt, um solche Anwendungsfälle speziell zu behandeln. Sie können einfach mehrere Links hinzufügen und verschiedene Handler für sie definieren. Es unterstützt auch das Hervorheben des gedrückten Links, wenn Sie für Touch-Feedback aufsetzen. Weitere Informationen finden Sie unter https://github.com/null09264/FRHyperLabel .

In Ihrem Fall könnte der Code folgendermaßen aussehen:

FRHyperLabel *label = [FRHyperLabel new];

NSString *string = @"This morph was generated with Face Dancer, Click to view in the app store.";
NSDictionary *attributes = @{NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]};

label.attributedText = [[NSAttributedString alloc]initWithString:string attributes:attributes];

[label setLinkForSubstring:@"Face Dancer" withLinkHandler:^(FRHyperLabel *label, NSString *substring){
    [[UIApplication sharedApplication] openURL:aURL];
}];

Beispiel-Screenshot (der Handler ist so eingestellt, dass in diesem Fall eine Warnung angezeigt wird, anstatt eine URL zu öffnen)

Faceancer


Wenn mein Text so aussieht, wurde dieser Morph mit Face Dancer erstellt. Klicken Sie im App Store Face Dancer auf die Ansicht Face to Dancer. Hier habe ich 3 Face Dancer, es hat nicht funktioniert
MANCHIKANTI KRISHNAKISHORE

1
In diesem Fall verwenden Sie - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; stattdessen die API . Bitte beachten Sie die Readme-Datei auf der Github-Seite.
Jinghan Wang

1
FRHyperLabel scheint nicht mehr zu funktionieren. Innerhalb von "characterIndexForPoint:" wird immer -1 zurückgegeben (nicht gefunden).
John Pang

Funktioniert bei mir nicht für mehrzeilige Labels. Die Erkennung von Zeichen ist falsch. 15-Zeichen-Link-Zeichenfolge ist nur auf einige erste Zeichen anklickbar, andere Zeichen tun nichts
Accid Bright

27

Kleinere Verbesserung der Lösung von ujell: Wenn Sie NSURL anstelle eines NSString verwenden, können Sie eine beliebige URL verwenden (z. B. benutzerdefinierte URLs).

NSURL *URL = [NSURL URLWithString: @"whatsapp://app"];
NSMutableAttributedString * str = [[NSMutableAttributedString alloc] initWithString:@"start Whatsapp"];
[str addAttribute: NSLinkAttributeName value:URL range: NSMakeRange(0, str.length)];
yourTextField.attributedText = str;

Habe Spaß!


21

Swift 4:

var string = "Google"
var attributedString = NSMutableAttributedString(string: string, attributes:[NSAttributedStringKey.link: URL(string: "http://www.google.com")!])

yourTextView.attributedText = attributedString

Swift 3.1:

var string = "Google"
var attributedString = NSMutableAttributedString(string: string, attributes:[NSLinkAttributeName: URL(string: "http://www.google.com")!])

yourTextView.attributedText = attributedString

Diese Antwort funktioniert so wie sie ist. Sie scheinen keine der Farben oder benutzerdefinierten Unterklassen zu benötigen, die andere Antworten verwenden.
Zeroimpl

19

Auch ich hatte eine ähnliche Anforderung, zuerst habe ich UILabel verwendet und dann festgestellt, dass UITextView besser ist. Ich habe dafür gesorgt, dass sich UITextView wie UILabel verhält, indem ich die Interaktion und das Scrollen deaktiviert habe, und eine Kategoriemethode erstellt, um NSMutableAttributedStringden Link zu Text so zu setzen, wie Karl es getan hat (+1 dafür). Dies ist meine Objektversion

-(void)setTextAsLink:(NSString*) textToFind withLinkURL:(NSString*) url
{
    NSRange range = [self.mutableString rangeOfString:textToFind options:NSCaseInsensitiveSearch];

    if (range.location != NSNotFound) {

        [self addAttribute:NSLinkAttributeName value:url range:range];
        [self addAttribute:NSForegroundColorAttributeName value:[UIColor URLColor] range:range];
    }
}

Sie können dann den folgenden Delegaten verwenden, um die Aktion auszuführen

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)url inRange:(NSRange)characterRange
{
    // do the task
    return YES;
}

1
Soweit ich das beurteilen kann, funktioniert die Einstellung NSForegroundColorAttributeNamein einem Bereich, in dem sie NSLinkAttributeNameangewendet wird, nicht. Egal was passiert, die linkTextAttributesvon UITextViewwerden stattdessen angewendet. Funktioniert NSForegroundColorAttributeNamefür Sie?
Dima

Sind Sie sicher, dass Sie sich nicht auch linkTextAttributesauf dasselbe einstellen ? oder vielleicht tintColor? Können Sie 2 Links in verschiedenen Farben in derselben Textansicht anzeigen lassen?
Dima

1
Hier ist ein Arbeitscode NSRange range = [self.text rangeOfString: textToFind options: NSCaseInsensitiveSearch]; if (range.location! = NSNotFound) {NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString: self.text]; [Zeichenfolge addAttribute: NSLinkAttributeName Wert: URL Bereich: Bereich]; [string addAttribute: NSForegroundColorAttributeName value: [UIColor blueColor] range: range]; self.text = @ ""; self.attributedText = string; }
Nosov Pavel

16

Verwenden Sie UITextView, um anklickbare Links zu unterstützen. Erstellen Sie eine zugeordnete Zeichenfolge mit dem folgenden Code

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:strSomeTextWithLinks];

Stellen Sie dann den UITextView-Text wie folgt ein

NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor redColor],

                                 NSUnderlineColorAttributeName: [UIColor blueColor],

                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

customTextView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;

Stellen Sie sicher, dass Sie das Verhalten "Auswählbar" der UITextView in XIB aktivieren.


15
Ich denke das ist die beste Lösung! Der Hinweis zum Aktivieren Selectableist wichtig!
LunaCodeGirl

Dies hat den Link für mich (iOS 7, 8) nicht unterstrichen. Ich musste NSUnderlineStyleAttributeName verwenden: [NSNumber numberWithInt: NSUnderlineStyleSingle]
Prewett

1
Die Auswahl ist die wichtigste und nicht intuitive Information!
Nicolas Massart

13

Das Herzstück meiner Frage war, dass ich anklickbare Links in Textansichten / Feldern / Beschriftungen erstellen wollte, ohne benutzerdefinierten Code schreiben zu müssen, um den Text zu bearbeiten und die Links hinzuzufügen. Ich wollte, dass es datengesteuert ist.

Ich habe endlich herausgefunden, wie es geht. Das Problem ist, dass IB eingebettete Links nicht berücksichtigt.

Darüber hinaus können Sie in der iOS-Version von NSAttributedStringkeine zugewiesene Zeichenfolge aus einer RTF-Datei initialisieren. Die OS X-Version von NSAttributedString verfügt über einen Initialisierer, der eine RTF-Datei als Eingabe verwendet.

NSAttributedString Entspricht dem NSCoding-Protokoll, sodass Sie es in / aus NSData konvertieren können

Ich habe ein OS X-Befehlszeilentool erstellt, das eine RTF-Datei als Eingabe verwendet und eine Datei mit der Erweiterung .data ausgibt, die die NSData von NSCoding enthält. Ich füge dann die .data-Datei in mein Projekt ein und füge ein paar Codezeilen hinzu, die den Text in die Ansicht laden. Der Code sieht folgendermaßen aus (dieses Projekt war in Swift):

/*
If we can load a file called "Dates.data" from the bundle and convert it to an attributed string,
install it in the dates field. The contents contain clickable links with custom URLS to select
each date.
*/
if
  let datesPath = NSBundle.mainBundle().pathForResource("Dates", ofType: "data"),
  let datesString = NSKeyedUnarchiver.unarchiveObjectWithFile(datesPath) as? NSAttributedString
{
  datesField.attributedText = datesString
}

Für Apps, die viel formatierten Text verwenden, erstelle ich eine Erstellungsregel, die Xcode mitteilt, dass alle RTF-Dateien in einem bestimmten Ordner Quell- und die DATA-Dateien die Ausgabe sind. Sobald ich das getan habe, füge ich einfach RTF-Dateien zum angegebenen Verzeichnis hinzu (oder bearbeite vorhandene Dateien), und der Erstellungsprozess stellt fest, dass sie neu / aktualisiert sind, führt das Befehlszeilentool aus und kopiert die Dateien in das App-Bundle. Es funktioniert wunderbar.

Ich habe einen Blog-Beitrag geschrieben, der auf ein Beispielprojekt (Swift) verweist, das die Technik demonstriert. Sie können es hier sehen:

Erstellen anklickbarer URLs in einem UITextField, die in Ihrer App geöffnet werden


11

Swift 3-Beispiel zum Erkennen von Aktionen auf zugewiesenen Textabgriffen

https://stackoverflow.com/a/44226491/5516830

let termsAndConditionsURL = TERMS_CONDITIONS_URL;
let privacyURL            = PRIVACY_URL;

override func viewDidLoad() {
    super.viewDidLoad()

    self.txtView.delegate = self
    let str = "By continuing, you accept the Terms of use and Privacy policy"
    let attributedString = NSMutableAttributedString(string: str)
    var foundRange = attributedString.mutableString.range(of: "Terms of use") //mention the parts of the attributed text you want to tap and get an custom action
    attributedString.addAttribute(NSLinkAttributeName, value: termsAndConditionsURL, range: foundRange)
    foundRange = attributedString.mutableString.range(of: "Privacy policy")
    attributedString.addAttribute(NSLinkAttributeName, value: privacyURL, range: foundRange)
    txtView.attributedText = attributedString
}

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "WebView") as! SKWebViewController

    if (URL.absoluteString == termsAndConditionsURL) {
        vc.strWebURL = TERMS_CONDITIONS_URL
        self.navigationController?.pushViewController(vc, animated: true)
    } else if (URL.absoluteString == privacyURL) {
        vc.strWebURL = PRIVACY_URL
        self.navigationController?.pushViewController(vc, animated: true)
    }
    return false
}

Ebenso können Sie mit der shouldInteractWith URLUITextFieldDelegate-Methode jede gewünschte Aktion hinzufügen.

Prost!!


7

Die schnelle Antwort lautet UITextView anstelle von UILabel. Sie müssen aktivieren Selectableund deaktivieren Editable.

Deaktivieren Sie dann die Bildlaufanzeigen und Bounces.

Bildschirmfoto

Bildschirmfoto

Meine Lösung mit NSMutableAttributedStringHTML-ZeichenfolgeNSHTMLTextDocumentType

NSString *s = @"<p><a href='https://itunes.apple.com/us/app/xxxx/xxxx?mt=8'>https://itunes.apple.com/us/app/xxxx/xxxx?mt=8</a></p>";

NSMutableAttributedString *text = [[NSMutableAttributedString alloc]
                                           initWithData: [s dataUsingEncoding:NSUnicodeStringEncoding]
                                           options: @{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
                                           documentAttributes: nil
                                           error: nil
                                           ];

cell.content.attributedText = text;

Dies. Ich konnte eine RTF-Datei aus meinem Ressourcenpaket lesen, in konvertieren NSAttributedString, als attributedTextmeine festlegen UITextViewund die Hyperlinks funktionieren einfach! Es wäre eine Menge Arbeit gewesen, den Bereich jedes Hyperlinks zu finden und ihn mithilfe von Attributen einzurichten.
Nicolas Miari

6

Ich habe eine Methode geschrieben, die einem String (fullString) einen Link (linkString) mit einer bestimmten URL (urlString) hinzufügt:

- (NSAttributedString *)linkedStringFromFullString:(NSString *)fullString withLinkString:(NSString *)linkString andUrlString:(NSString *)urlString
{
    NSRange range = [fullString rangeOfString:linkString options:NSLiteralSearch];
    NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:fullString];

    NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
    paragraphStyle.alignment = NSTextAlignmentCenter;
    NSDictionary *attributes = @{NSForegroundColorAttributeName:RGB(0x999999),
                                 NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-Light" size:10],
                                 NSParagraphStyleAttributeName:paragraphStyle};
    [str addAttributes:attributes range:NSMakeRange(0, [str length])];
    [str addAttribute: NSLinkAttributeName value:urlString range:range];

    return str;
}

Sie sollten es so nennen:

NSString *fullString = @"A man who bought the Google.com domain name for $12 and owned it for about a minute has been rewarded by Google for uncovering the flaw.";
NSString *linkString = @"Google.com";
NSString *urlString = @"http://www.google.com";

_youTextView.attributedText = [self linkedStringFromFullString:fullString withLinkString:linkString andUrlString:urlString];

Es ist anklickbar, aber es öffnet den Link oder irgendetwas nicht. Es klickt einfach wie eine Schaltfläche, die nichts bewirkt.
Reza.Ab

5

Ich musste weiterhin ein reines UILabel verwenden, das von meinem Tap-Erkenner so genannt wurde (dies basiert auf der Antwort von Malex hier: Zeichenindex am Berührungspunkt für UILabel )

UILabel* label = (UILabel*)gesture.view;
CGPoint tapLocation = [gesture locationInView:label];

// create attributed string with paragraph style from label

NSMutableAttributedString* attr = [label.attributedText mutableCopy];
NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.alignment = label.textAlignment;

[attr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, label.attributedText.length)];

// init text storage

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attr];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];

// init text container

NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(label.frame.size.width, label.frame.size.height+100) ];
textContainer.lineFragmentPadding  = 0;
textContainer.maximumNumberOfLines = label.numberOfLines;
textContainer.lineBreakMode        = label.lineBreakMode;

[layoutManager addTextContainer:textContainer];

// find tapped character

NSUInteger characterIndex = [layoutManager characterIndexForPoint:tapLocation
                                                  inTextContainer:textContainer
                         fractionOfDistanceBetweenInsertionPoints:NULL];

// process link at tapped character

[attr enumerateAttributesInRange:NSMakeRange(characterIndex, 1)
                                         options:0
                                      usingBlock:^(NSDictionary<NSString *,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
                                          if (attrs[NSLinkAttributeName]) {
                                              NSString* urlString = attrs[NSLinkAttributeName];
                                              NSURL* url = [NSURL URLWithString:urlString];
                                              [[UIApplication sharedApplication] openURL:url];
                                          }
                                      }];

Dies war sehr hilfreich, ich konnte keine Indizes von Zeichen in der letzten Zeile erhalten. Ihr Code hat die +100 auf dem textContainer, wenn Sie CGSize starten, was für mich nicht sehr sinnvoll ist, aber es hat den Trick getan.
Blueether

4

Aktualisieren:

Meine Frage bestand aus zwei Hauptteilen:

  1. So erstellen Sie einen Link, bei dem sich der für den anklickbaren Link angezeigte Text von dem tatsächlich aufgerufenen Link unterscheidet:
  2. So richten Sie die Links ein, ohne benutzerdefinierten Code zum Festlegen der Attribute für den Text verwenden zu müssen.

Es stellt sich heraus, dass iOS 7 die Möglichkeit hinzugefügt hat, zugeordneten Text von zu laden NSData.

Ich habe eine benutzerdefinierte Unterklasse erstellt UITextView, die die Vorteile von nutzt@IBInspectable Attribut und es Ihnen ermöglicht, Inhalte aus einer RTF-Datei direkt in IB zu laden. Sie geben einfach den Dateinamen in IB ein und die benutzerdefinierte Klasse erledigt den Rest.

Hier sind die Details:

In iOS 7 NSAttributedStringerlangte die Methode initWithData:options:documentAttributes:error:. Mit dieser Methode können Sie einen NSAttributedString aus einem NSData-Objekt laden. Sie können zuerst eine RTF-Datei in NSData laden und dann initWithData:options:documentAttributes:error:diese NSData in Ihre Textansicht laden. (Beachten Sie, dass es auch eine Methode gibt initWithFileURL:options:documentAttributes:error:, die eine zugewiesene Zeichenfolge direkt aus einer Datei lädt. Diese Methode wurde jedoch in iOS 9 nicht mehr unterstützt. Es ist sicherer, die Methode zu verwenden initWithData:options:documentAttributes:error:, die nicht veraltet war.

Ich wollte eine Methode, mit der ich anklickbare Links in meine Textansichten installieren kann, ohne Code für die von mir verwendeten Links erstellen zu müssen.

Die Lösung bestand darin, eine benutzerdefinierte Unterklasse von UITextView zu erstellen, die ich aufrufe, RTF_UITextViewund ihr eine @IBInspectableEigenschaft mit dem Namen zu geben RTF_Filename. Durch Hinzufügen des @IBInspectableAttributs zu einer Eigenschaft wird diese Eigenschaft im Interface Builder im "Attributes Inspector" verfügbar gemacht. Sie können diesen Wert dann über IB ohne benutzerdefinierten Code festlegen.

Ich @IBDesignablehabe meiner benutzerdefinierten Klasse auch ein Attribut hinzugefügt . Das @IBDesignableAttribut teilt Xcode mit, dass eine laufende Kopie Ihrer benutzerdefinierten Ansichtsklasse im Interface Builder installiert werden soll, damit Sie sie in der grafischen Anzeige Ihrer Ansichtshierarchie sehen können. () Leider @IBDesignablescheint die Eigenschaft für diese Klasse schuppig zu sein. Es hat funktioniert, als ich es zum ersten Mal hinzugefügt habe, aber dann habe ich den Nur-Text-Inhalt meiner Textansicht gelöscht und die anklickbaren Links in meiner Ansicht sind verschwunden und ich konnte sie nicht zurückbekommen.)

Der Code für meine RTF_UITextViewist sehr einfach. Zusätzlich zum Hinzufügen des @IBDesignableAttributs und einer RTF_FilenameEigenschaft mit dem @IBInspectableAttribut habe ich didSet()der RTF_FilenameEigenschaft eine Methode hinzugefügt . Die didSet()Methode wird jedes Mal aufgerufen, wenn sich der Wert der RTF_FilenameEigenschaft ändert. Der Code für die didSet()Methode ist recht einfach:

@IBDesignable
class RTF_UITextView: UITextView
{
  @IBInspectable
  var RTF_Filename: String?
    {
    didSet(newValue)
    {
      //If the RTF_Filename is nil or the empty string, don't do anything
      if ((RTF_Filename ?? "").isEmpty)
      {
        return
      }
      //Use optional binding to try to get an URL to the
      //specified filename in the app bundle. If that succeeds, try to load
      //NSData from the file.
      if let fileURL = NSBundle.mainBundle().URLForResource(RTF_Filename, withExtension: "rtf"),
        
        //If the fileURL loads, also try to load NSData from the URL.
        let theData = NSData(contentsOfURL: fileURL)
      {
        var aString:NSAttributedString
        do
        {
          //Try to load an NSAttributedString from the data
          try
            aString = NSAttributedString(data: theData,
              options: [:],
              documentAttributes:  nil
          )
          //If it succeeds, install the attributed string into the field.
          self.attributedText = aString;
        }
        catch
        {
          print("Nerp.");
        }
      }
      
    }
  }
}

Beachten Sie, dass es möglicherweise besser ist, den obigen Code als Erweiterung von UITextView als als benutzerdefinierte Unterklasse einzurichten, wenn Sie mit der Eigenschaft @IBDesignable nicht zuverlässig eine Vorschau Ihres gestalteten Textes im Interface Builder anzeigen können. Auf diese Weise können Sie es in jeder Textansicht verwenden, ohne die Textansicht in die benutzerdefinierte Klasse ändern zu müssen.

Siehe meine andere Antwort, wenn Sie iOS-Versionen vor iOS 7 unterstützen müssen.

Sie können ein Beispielprojekt mit dieser neuen Klasse von gitHub herunterladen:

DatesInSwift-Demo-Projekt auf Github


3

Finden Sie einfach eine codefreie Lösung für UITextView: Geben Sie hier die Bildbeschreibung ein

Aktivieren Sie die Optionen Erkennung-> Links. Die URL und auch die E-Mail werden erkannt und können angeklickt werden.


3
Das macht Links anklickbar. Ich möchte einen benutzerlesbaren Text haben, hinter dem ein Link steht. Siehe das Beispiel in meiner ursprünglichen Frage.
Duncan C

Ja, meine Antwort gilt nur für den Fall, dass der Link mit dem Text übereinstimmt. Wenn der Link ein anderes Zeug ist, würde ich der Antwort von @ ujell folgen.
Bill Chan

3
Meine Frage bezog sich ganz speziell auf anklickbaren Text, der etwas anderes als die URL anzeigt. Sie haben nicht mehr als einen Blick auf die Frage geworfen, oder?
Duncan C

1
Ich habe nicht anderen Zwecken gedient, aber dies ist sicherlich das, wonach ich gesucht habe ... eine Möglichkeit, Links in meiner Chat-Anwendung anklickbar zu machen. Bingo Ich habe diesen Artikel gefunden ... danke! Wünschte, xcode würde die Aktivierung von Twitter und Hash-Tags ermöglichen.
MizAkita

Dies funktioniert auch mit benutzerdefiniertem Text, der aus einem unformatierten Link besteht. Denken Sie daran, Verhalten -> Auswählbar und Erkennung -> Links auszuwählen.
krlbsk

3

Schnelle Version:

    // Attributed String for Label
    let plainText = "Apkia"
    let styledText = NSMutableAttributedString(string: plainText)
    // Set Attribuets for Color, HyperLink and Font Size
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(14.0), NSLinkAttributeName:NSURL(string: "http://apkia.com/")!, NSForegroundColorAttributeName: UIColor.blueColor()]
    styledText.setAttributes(attributes, range: NSMakeRange(0, plainText.characters.count))
    registerLabel.attributedText = styledText

3

Verwenden Sie UITextView und legen Sie dataDetectorTypes für Link fest.

so was:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

Wenn Sie Link, Telefonnummer, Adresse usw. erkennen möchten, dann

testTextView.dataDetectorTypes = .all

3
Nein. Dadurch können Sie nur Links anklickbar machen. Meine Frage ist spezifisch dafür, beliebigen Text wie "hier klicken" anklickbar zu machen, nicht eine URL wiehttp://somedomain/someurl?param=value
Duncan C

2

Eine schnelle Ergänzung zu Duncan Cs ursprünglicher Beschreibung des IB-Verhaltens. Er schreibt: "Es ist trivial, Hyperlinks in einer UITextView anklickbar zu machen. Sie setzen einfach das Kontrollkästchen" Links erkennen "in der Ansicht in IB, und es erkennt http-Links und wandelt sie in Hyperlinks um."

Ich habe die Erfahrung gemacht (zumindest in xcode 7), dass Sie auch das Verhalten "Bearbeitbar" deaktivieren müssen, damit die URLs erkannt und angeklickt werden können.


2

Falls Sie Probleme mit dem haben, was @Karl Nosworthy und @esilver oben angegeben haben, habe ich die Erweiterung NSMutableAttributedString auf die Swift 4-Version aktualisiert.

extension NSMutableAttributedString {

public func setAsLink(textToFind:String, linkURL:String) -> Bool {

    let foundRange = self.mutableString.range(of: textToFind)
    if foundRange.location != NSNotFound {
         _ = NSMutableAttributedString(string: textToFind)
        // Set Attribuets for Color, HyperLink and Font Size
        let attributes = [NSFontAttributeName: UIFont.bodyFont(.regular, shouldResize: true), NSLinkAttributeName:NSURL(string: linkURL)!, NSForegroundColorAttributeName: UIColor.blue]

        self.setAttributes(attributes, range: foundRange)
        return true
    }
    return false
  }
}


0

Wenn Sie den NSLinkAttributeName in einer UITextView verwenden möchten, können Sie die AttributedTextView-Bibliothek verwenden. Es ist eine UITextView-Unterklasse, die es sehr einfach macht, mit diesen umzugehen. Weitere Informationen finden Sie unter: https://github.com/evermeer/AttributedTextView

Sie können jeden Teil des Textes wie folgt interagieren lassen (wobei textView1 ein UITextView-IBoutlet ist):

textView1.attributer =
    "1. ".red
    .append("This is the first test. ").green
    .append("Click on ").black
    .append("evict.nl").makeInteract { _ in
        UIApplication.shared.open(URL(string: "http://evict.nl")!, options: [:], completionHandler: { completed in })
    }.underline
    .append(" for testing links. ").black
    .append("Next test").underline.makeInteract { _ in
        print("NEXT")
    }
    .all.font(UIFont(name: "SourceSansPro-Regular", size: 16))
    .setLinkColor(UIColor.purple) 

Und für den Umgang mit Hashtags und Erwähnungen können Sie folgenden Code verwenden:

textView1.attributer = "@test: What #hashtags do we have in @evermeer #AtributedTextView library"
    .matchHashtags.underline
    .matchMentions
    .makeInteract { link in
        UIApplication.shared.open(URL(string: "https://twitter.com\(link.replacingOccurrences(of: "@", with: ""))")!, options: [:], completionHandler: { completed in })
    }


0
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:strSomeTextWithLinks];

NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor redColor],   
                                 NSUnderlineColorAttributeName: [UIColor blueColor],
                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

customTextView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;

WICHTIGE PUNKTE:

  • Stellen Sie sicher, dass Sie das Verhalten "Auswählbar" der UITextView in XIB aktivieren.
  • Stellen Sie sicher, dass Sie das "bearbeitbare" Verhalten von UITextView in XIB deaktivieren.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.