Come posso creare un collegamento cliccabile in un NSAttributedString?


200

È banale rendere i collegamenti ipertestuali selezionabili in a UITextView. È sufficiente impostare la casella di controllo "Rileva collegamenti" nella vista in IB e rileva i collegamenti HTTP e li trasforma in collegamenti ipertestuali.

Tuttavia, ciò significa che ciò che l'utente vede è il link "non elaborato". I file RTF e HTML consentono entrambi di impostare una stringa leggibile dall'utente con un collegamento "dietro" ad essa.

È facile installare il testo attribuito in una vista di testo (o un UILabeloUITextField , per quella materia). Tuttavia, quando quel testo attribuito include un collegamento, non è selezionabile.

Esiste un modo per rendere il testo leggibile dall'utente selezionabile in a UITextView, UILabeloUITextField ?

Il markup è diverso su SO, ma ecco l'idea generale. Quello che voglio è un testo come questo:

Questo morph è stato generato con Face Dancer , fai clic per visualizzarlo nell'app store.

L'unica cosa che posso ottenere è questa:

Questo morph è stato generato con Face Dancer, fai clic su http://example.com/facedancer per visualizzarlo nell'app store.


Prova questo esempio .. IFTweetLabel Spero che ti aiuti ..
Vidhyan e


Bel lavoro che ha superato i 100K in un batter d'occhio. Benvenuti nel club 100K. Meritato!
vacawama,

@vacawama, aspetta, quando è successo? L'ultima volta che ho visto ero a ≈98k! (Ho sentito delle voci che ottieni un po 'di SO swag come membro del club 100k?)
Duncan C

Hanno modificato i voti sulle domande da +5 a +10, quindi se avessi 800 voti aumenteresti di +4000 in un lampo. Sto ancora aspettando 100k swag (attraversato ad aprile). Qualcosa sul cambiamento dei venditori di swag ...
vacawama,

Risposte:


156

Utilizzare NSMutableAttributedString .

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

Modifica :

Non si tratta direttamente della domanda, ma solo per chiarire UITextFielde UILabelnon supporta l'apertura di URL. Se si desidera utilizzare UILabelcon i collegamenti è possibile controllare TTTAttributedLabel .

Inoltre si dovrebbe impostare dataDetectorTypesil valore della vostra UITextViewal UIDataDetectorTypeLinko UIDataDetectorTypeAllagli URL aperti quando si fa clic. Oppure puoi usare il metodo delegato come suggerito nei commenti.


7
Sì, funziona, basta inserirlo in un UITextView e sovrascrivere il metodo delegato: - (BOOL) textView: (UITextView *) textView shouldInteractWithURL: (NSURL *) url inRange: (NSRange) characterRange
Yunus Nedim Mehel

Questo non funziona in un UILabel - non succede nulla quando tocchi il campo.
Jack BeNimble il

7
@saboehnke intendi chiamare un metodo quando si fa clic sul collegamento? in tal caso implementare il metodo delegato, fornire un URL fittizio come attributo e chiamare il metodo in- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
ujell

2
Non so come funzioni. Il valore dell'attributo dovrebbe essere il tipo di NSURL. ----[str addAttribute: NSLinkAttributeName value: [NSURL URLWithString:@"http://www.google.com"] range: NSMakeRange(0, str.length)];
Nirav Dangi,

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

143

L'ho trovato davvero utile, ma dovevo farlo in parecchi posti, quindi ho concluso il mio approccio con una semplice estensione a 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
   }
}

Esempio di utilizzo:

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

if linkWasSet {
    // adjust more attributedString properties
}

Objective-C

Ho appena soddisfatto l'obbligo di fare lo stesso in un progetto Objective-C puro, quindi ecco la categoria Objective-C.

@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

Esempio di utilizzo:

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

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

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

Assicurarsi che l'attributo Comportamento di NSTextField sia impostato come Selezionabile. Attributo del comportamento Xcode NSTextField


Un rapido esempio di utilizzo / implementazione di questo sarebbe molto apprezzato.
ioopl,

3
@ioop. Ho aggiunto un piccolo esempio al post originale sopra, spero che sia di aiuto.
Karl Nosworthy,

7
Questo ha funzionato correttamente. Voglio solo dire che devi rendere UITextView selezionabile per consentire al link di essere cliccabile
lujop

1
@felecia genet, nelle implementazioni di Objective C e Swift il metodo restituisce un risultato booleano per indicare se si sono verificati una corrispondenza e un set risultante. L'errore che stai vedendo è perché non stai acquisendo quel risultato, il che va bene. È possibile acquisire tale risultato assegnandolo a una variabile locale o regolare il metodo per impedirne la restituzione del valore booleano se si adatta meglio alle proprie esigenze. Spero che aiuti?
Karl Nosworthy,

1
Nessun problema @feleciagenet, ho aggiunto la memorizzazione e il controllo del risultato del metodo sia negli esempi Swift che ObjectiveC.
Karl Nosworthy,

34

Ho appena creato una sottoclasse di UILabel per affrontare in modo specifico tali casi d'uso. È possibile aggiungere più collegamenti facilmente e definire gestori diversi per essi. Supporta anche l'evidenziazione del collegamento premuto quando si tocca verso il basso per il feedback al tocco. Fare riferimento a https://github.com/null09264/FRHyperLabel .

Nel tuo caso, il codice potrebbe essere così:

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];
}];

Schermata di esempio (il gestore è impostato per visualizzare un avviso anziché aprire un URL in questo caso)

facedancer


se supponiamo che il mio testo sia così Questo metamorfosi è stato generato con Face Dancer, vista Click to Face Dancer nell'app store Face Dancer. qui sto avendo 3 Face Dancer non funzionava per questo
MANCHIKANTI KRISHNAKISHORE

1
In questo caso, utilizzare - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; invece l'API . Fare riferimento al file Leggimi nella pagina di github.
Jinghan Wang,

1
FRHyperLabel sembra non funzionare più. All'interno di "characterIndexForPoint:", restituisce sempre -1 (non trovato).
John Pang,

Non funziona per me per l'etichetta multilinea. Il rilevamento dei personaggi è sbagliato. La stringa di collegamento di 15 caratteri è selezionabile solo su alcuni primi caratteri, altri caratteri non fanno nulla
Accid Bright

27

Miglioramento minore della soluzione di ujell: se usi NSURL invece di una NSString, puoi usare qualsiasi URL (es. URL personalizzati)

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;

Divertiti!


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

Questa risposta funziona perfettamente così com'è. Non sembra aver bisogno di nessuna delle sottoclassi di colorazione o personalizzate utilizzate da altre risposte.
zeroimpl

19

Anch'io avevo un requisito simile, inizialmente ho usato UILabel e poi ho capito che UITextView è migliore. Ho fatto UITextView comportarsi come UILabel disabilitando l'interazione e lo scorrimento e ho creato un metodo di categoria per NSMutableAttributedStringimpostare il collegamento al testo come quello che aveva fatto Karl (+1 per quello) questa è la mia versione oggettiva

-(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];
    }
}

è possibile utilizzare il delegato di seguito quindi per gestire l'azione

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

1
Per quanto ne so, l'impostazione NSForegroundColorAttributeNamein un intervallo in cui NSLinkAttributeNameviene applicata non funziona. Non importa cosa, l' linkTextAttributesdel UITextViewsi applicano invece. Funziona NSForegroundColorAttributeNameper te?
Dima,

Sei sicuro di non impostare anche linkTextAttributesla stessa cosa? o forse tintColor? Sei in grado di far apparire 2 link in colori diversi nella stessa visualizzazione di testo?
Dima,

1
Ecco un codice funzionante NSRange range = [self.text rangeOfString: textToFind opzioni: NSCaseInsensitiveSearch]; if (range.location! = NSNotFound) {NSMutableAttributedString * string = [[[NSMutableAttributedString alloc] initWithString: self.text]; [string addAttribute: NSLinkAttributeName value: url range: range]; [string addAttribute: NSForegroundColorAttributeName valore: [UIColor blueColor] intervallo: intervallo]; self.text = @ ""; self.attributedText = string; }
Nosov Pavel,

16

Usa UITextView supporta collegamenti cliccabili. Crea una stringa attribuita usando il seguente codice

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

Quindi impostare il testo UITextView come segue

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

                                 NSUnderlineColorAttributeName: [UIColor blueColor],

                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

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

Assicurati di abilitare il comportamento "Selezionabile" di UITextView in XIB.


15
Penso che questa sia la soluzione migliore! La nota sull'abilitazione Selectableè importante!
LunaCodeGirl

Questo non ha sottolineato il collegamento per me (iOS 7, 8). Avevo bisogno di usare NSUnderlineStyleAttributeName: [NSNumber numberWithInt: NSUnderlineStyleSingle]
prewett

1
renderlo selezionabile è l'informazione più importante e non intuitiva!
Nicolas Massart,

13

Il cuore della mia domanda era che volevo essere in grado di creare collegamenti cliccabili in viste / campi / etichette di testo senza dover scrivere codice personalizzato per manipolare il testo e aggiungere i collegamenti. Volevo che fosse basato sui dati.

Alla fine ho capito come farlo. Il problema è che IB non rispetta i collegamenti incorporati.

Inoltre, la versione iOS di NSAttributedStringnon consente di inizializzare una stringa attribuita da un file RTF. La versione OS X di NSAttributedString fa avere un inizializzatore che prende un file RTF come input.

NSAttributedString è conforme al protocollo NSCoding, quindi è possibile convertirlo in / da NSData

Ho creato uno strumento da riga di comando OS X che accetta un file RTF come input e genera un file con estensione .data che contiene NSData da NSCoding. Ho quindi inserito il file .data nel mio progetto e ho aggiunto un paio di righe di codice che caricano il testo nella vista. Il codice è simile al seguente (questo progetto era 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
}

Per le app che usano molto testo formattato, creo una regola di generazione che dice a Xcode che tutti i file .rtf in una determinata cartella sono di origine e i file .data sono l'output. Una volta fatto ciò, aggiungo semplicemente i file .rtf alla directory designata (o modifica i file esistenti) e il processo di compilazione scopre che sono nuovi / aggiornati, esegue lo strumento da riga di comando e copia i file nel bundle dell'app. Funziona magnificamente.

Ho scritto un post sul blog che collega a un progetto (Swift) di esempio che dimostra la tecnica. Potete vederlo qui:

Creazione di URL cliccabili in un UITextField che si apre nella tua app


11

Swift 3 esempio per rilevare azioni sui tocchi di testo attribuiti

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
}

Come saggio puoi aggiungere qualsiasi azione tu voglia shouldInteractWith URL metodo UITextFieldDelegate.

Saluti!!


7

La risposta rapida sta usando UITextView invece di UILabel. Devi abilitare Selectablee disabilitareEditable .

Quindi disabilitare gli indicatori di scorrimento e i rimbalzi.

Immagine dello schermo

Immagine dello schermo

La mia soluzione utilizza NSMutableAttributedStringdalla stringa HTMLNSHTMLTextDocumentType

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;

Questo. Sono stato in grado di leggere un file RTF dal mio pacchetto di risorse, convertirlo in NSAttributedString, impostarlo come il attributedTextmio UITextViewe i collegamenti ipertestuali funzionano! Sarebbe stato molto difficile trovare l'intervallo di ciascun collegamento ipertestuale e configurarlo utilizzando gli attributi.
Nicolas Miari,

6

Ho scritto un metodo che aggiunge un collegamento (linkString) a una stringa (fullString) con un determinato url (urlString):

- (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;
}

Dovresti chiamarlo così:

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];

È cliccabile ma non apre il link o altro. fa semplicemente clic come un pulsante che non fa nulla.
Reza,

5

Dovevo continuare a utilizzare un UILabel puro, così chiamato dal mio riconoscimento dei tocchi (questo si basa sulla risposta di malex qui: indice dei caratteri al punto di contatto per 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];
                                          }
                                      }];

Questo è stato abbastanza utile, non sono stato in grado di ottenere gli indici dai personaggi nell'ultima riga. Il tuo codice ha il +100 su textContainer quando si avvia CGSize, il che non ha molto senso per me, ma ha funzionato.
blueether

4

Aggiornare:

C'erano 2 parti chiave della mia domanda:

  1. Come creare un collegamento in cui il testo visualizzato per il collegamento selezionabile è diverso dal collegamento effettivo richiamato:
  2. Come impostare i collegamenti senza dover utilizzare il codice personalizzato per impostare gli attributi sul testo.

Si scopre che iOS 7 ha aggiunto la possibilità di caricare il testo attribuito da NSData .

Ho creato una sottoclasse personalizzata UITextViewche sfrutta l' @IBInspectableattributo e consente di caricare i contenuti da un file RTF direttamente in IB. Basta digitare il nome file in IB e la classe personalizzata fa il resto.

Ecco i dettagli:

In iOS 7, ha NSAttributedStringguadagnato il metodo initWithData:options:documentAttributes:error:. Questo metodo consente di caricare un NSAttributedString da un oggetto NSData. È innanzitutto possibile caricare un file RTF in NSData, quindi utilizzare initWithData:options:documentAttributes:error:per caricare tale NSData nella vista di testo. (Si noti che esiste anche un metodo initWithFileURL:options:documentAttributes:error:che caricherà una stringa attribuita direttamente da un file, ma tale metodo è stato deprecato in iOS 9. È più sicuro utilizzare il metodo initWithData:options:documentAttributes:error:, che non è stato deprecato.

Volevo un metodo che mi permettesse di installare collegamenti cliccabili nelle mie visualizzazioni di testo senza dover creare alcun codice specifico per i collegamenti che stavo usando.

La soluzione che mi è venuta in mente è stata quella di creare una sottoclasse personalizzata di UITextView che chiamo RTF_UITextViewe dargli una @IBInspectableproprietà chiamata RTF_Filename. Aggiungere il@IBInspectable dell'attributo a una proprietà fa sì che Interface Builder esponga quella proprietà in "Impostazioni attributi". È quindi possibile impostare quel valore da IB senza codice personalizzato.

Ho anche aggiunto un @IBDesignableattributo alla mia classe personalizzata. L' @IBDesignableattributo dice a Xcode che dovrebbe installare una copia in esecuzione della classe di visualizzazione personalizzata nel builder Interface in modo che tu possa vederlo nella visualizzazione grafica della gerarchia della vista. () Sfortunatamente, per questa classe, la @IBDesignableproprietà sembra essere traballante. Ha funzionato quando l'ho aggiunto per la prima volta, ma poi ho eliminato il contenuto in testo normale della mia vista di testo e i collegamenti cliccabili nella mia vista sono andati via e non sono stato in grado di recuperarli.)

Il mio codice RTF_UITextViewè molto semplice. Oltre ad aggiungere l' @IBDesignableattributo e una RTF_Filenameproprietà con l' @IBInspectableattributo, ho aggiunto un didSet()metodo alla RTF_Filenameproprietà. Il didSet()metodo viene chiamato ogni volta che il valore della RTF_Filenameproprietà cambia. Il codice per il didSet()metodo è abbastanza semplice:

@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.");
        }
      }
      
    }
  }
}

Nota che se la proprietà @IBDesignable non ti consentirà in modo affidabile di visualizzare l'anteprima del testo con stile nel builder Interface, potrebbe essere meglio impostare il codice sopra come estensione di UITextView anziché come sottoclasse personalizzata. In questo modo è possibile utilizzarlo in qualsiasi vista di testo senza dover modificare la vista di testo nella classe personalizzata.

Vedi la mia altra risposta se è necessario supportare versioni iOS precedenti a iOS 7.

Puoi scaricare un progetto di esempio che include questa nuova classe da gitHub:

Progetto demo DatesInSwift su Github


3

Basta trovare una soluzione senza codice per UITextView: inserisci qui la descrizione dell'immagine

Abilita Rilevamento-> Opzioni link, l'URL e anche l'e-mail saranno rilevati e cliccabili!


3
Ciò rende i collegamenti selezionabili. Voglio avere un testo leggibile dall'utente che abbia un link dietro di esso. Vedi l'esempio nella mia domanda originale.
Duncan C,

Sì, la mia risposta si applica solo nel caso in cui il collegamento sia lo stesso del testo. Se il link è un'altra cosa, seguirei la risposta di @ ujell.
Bill Chan,

3
La mia domanda era molto specifica sul testo cliccabile che visualizza qualcosa di diverso dall'URL. Non hai fatto altro che dare un'occhiata alla domanda, vero?
Duncan C,

1
non serviva ad altri scopi ma sicuramente questo è quello che sono arrivato a cercare stack ... un modo per rendere cliccabili i collegamenti nella mia applicazione di chat. Bingo Ho trovato questo articolo ... grazie! Wish xcode consentirebbe l'abilitazione di Twitter e tag hash.
Miz Akita

Funziona anche con testo personalizzato installato su link non elaborato. Ricordarsi di selezionare Comportamento -> Selezionabile e Rilevamento -> Collegamenti.
krlbsk,

3

Versione rapida:

    // 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

Usa UITextView e imposta dataDetectorTypes per Link.

come questo:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

Se si desidera rilevare collegamento, numero di telefono, indirizzo ecc

testTextView.dataDetectorTypes = .all

3
No. Questo ti consente solo di rendere cliccabili i link. La mia domanda è specifica per rendere cliccabile il testo arbitrario come "fai clic qui", non un URL comehttp://somedomain/someurl?param=value
Duncan C

2

Una rapida aggiunta alla descrizione originale di Duncan C rispetto al comportamento IB. Scrive: "È banale rendere i collegamenti ipertestuali selezionabili in un UITextView. Basta impostare la casella di controllo" Rileva collegamenti "sulla vista in IB, e rileva i collegamenti http e li trasforma in collegamenti ipertestuali."

La mia esperienza (almeno in xcode 7) è che devi anche deselezionare il comportamento "Modificabile" affinché gli URL vengano rilevati e cliccabili.


2

Nel caso in cui tu abbia problemi con ciò che @Karl Nosworthy e @esilver avevano fornito sopra, ho aggiornato l'estensione NSMutableAttributedString alla sua versione di Swift 4.

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

Se si desidera utilizzare NSLinkAttributeName in un UITextView, è possibile utilizzare la libreria AttributedTextView. È una sottoclasse UITextView che semplifica la gestione di questi. Per maggiori informazioni, consultare: https://github.com/evermeer/AttributedTextView

Puoi far interagire qualsiasi parte del testo in questo modo (dove textView1 è un IBoutlet UITextView):

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) 

E per gestire hashtag e menzioni puoi usare un codice come questo:

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;

PUNTI CHIAVE:

  • Assicurati di abilitare il comportamento "Selezionabile" di UITextView in XIB.
  • Assicurati di disabilitare il comportamento "Modificabile" di UITextView in XIB.
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.