Как я могу сделать кликабельную ссылку в NSAttributedString?

200

Сделать гиперссылки кликабельными в UITextView. Вы просто устанавливаете флажок «обнаруживать ссылки» в представлении в IB, и он обнаруживает ссылки HTTP и превращает их в гиперссылки.

Тем не менее, это все еще означает, что то, что видит пользователь, является «сырой» ссылкой. RTF-файлы и HTML позволяют настроить читаемую пользователем строку со ссылкой «позади».

Атрибутивный текст легко установить в текстовом представлении (или, UILabelили UITextField, если на то пошло). Однако, когда этот атрибутивный текст содержит ссылку, он не кликабелен.

Есть ли способ , чтобы сделать пользовательский читаемый текст кликабельным в UITextView, UILabelили UITextField?

Разметка отличается от SO, но вот общая идея. То, что я хочу, это текст, как это:

Этот морф был создан с помощью Face Dancer. Нажмите, чтобы просмотреть в магазине приложений.

Единственное, что я могу получить, это:

Этот морф был создан с помощью Face Dancer. Нажмите на http://example.com/facedancer для просмотра в магазине приложений.

Дункан С
источник
Попробуйте этот пример .. IFTweetLabel Надеюсь, что это помогает ..
Vidhyanand
Хорошая работа, пролетевшая 100K в мгновение ока. Добро пожаловать в клуб 100K. Хорошо заслужено!
Vacawama
@vacawama, подожди, когда это случилось? Я был в ≈98k в последний раз, когда я смотрел! (Я слышал слухи о том, что вы получили какую-то ТАКУЮ добычу в качестве члена клуба 100k?)
Duncan C
Они изменили количество голосов на вопросы с +5 до +10, поэтому, если у вас было 800 голосов, вы бы сразу получили +4000. Я все еще жду 100к хаба (пересек в апреле). Кое-что о смене продавцов
хабаров

Ответы:

156

Используйте NSMutableAttributedString .

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

Редактировать :

Речь идет не о самом вопросе, а только о том, чтобы уточнить, UITextFieldи UILabelне поддерживает открытие URL. Если вы хотите использовать UILabelсо ссылками, вы можете проверить TTTAttributedLabel .

Кроме того, вы должны установить dataDetectorTypesценность ваших UITextViewк UIDataDetectorTypeLinkили UIDataDetectorTypeAllв открытых URL - адресов при нажатии. Или вы можете использовать метод делегата, как предложено в комментариях.

ujell
источник
7
Да, это работает, просто положить его внутри метода UITextView и переопределение делегата: - (BOOL) TextView: (UITextView *) TextView shouldInteractWithURL: (NSURL *) URL InRange: (NSRange) ДиапазонСимволов
Юнус Nedim Mehel
Это не работает в UILabel - ничего не происходит, когда вы нажимаете на поле.
Джек БеНимбл
7
@saboehnke Вы имеете в виду вызов метода, когда ссылка нажата? если это так, реализуйте метод делегата, укажите фиктивный URL в качестве атрибута и вызовите свой метод в- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
ujell,
2
Я не знаю, как это работает. Значение атрибута должно быть типом NSURL. ----[str addAttribute: NSLinkAttributeName value: [NSURL URLWithString:@"http://www.google.com"] range: NSMakeRange(0, str.length)];
Нирав Данги
1
@NiravDangi отNSAttributedString.h UIKIT_EXTERN NSString * const NSLinkAttributeName NS_AVAILABLE(10_0, 7_0); // NSURL (preferred) or NSString
Ахмед Навар
143

Я нашел это действительно полезным, но мне нужно было сделать это в нескольких местах, поэтому я обернул свой подход в простое расширение NSMutableAttributedString:

Свифт 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
   }
}

Пример использования:

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

if linkWasSet {
    // adjust more attributedString properties
}

Objective-C

Я только что выполнил требование сделать то же самое в чистом проекте Objective-C, так что вот категория 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

Пример использования:

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

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

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

Удостоверьтесь, что атрибут Поведения NSTextField установлен как Выбираемый. Атрибут поведения Xcode NSTextField

Карл Носворти
источник
Быстрый пример использования / реализации этого был бы очень признателен.
ioopl
3
@ioop. Я добавил очень маленький пример к оригинальному сообщению выше, надеюсь, это поможет.
Карл Носворти
7
Это сработало правильно. Просто хочу сказать, что вам нужно сделать свой UITextView доступным для выбора, чтобы ссылка была кликабельной
lujop
1
@felecia genet, в реализациях Objective C и Swift метод возвращает логический результат, чтобы указать, имело ли место совпадение и результирующий набор. Ошибка, которую вы видите, заключается в том, что вы не фиксируете этот результат - это нормально. Вы можете либо захватить этот результат, присвоив его локальной переменной, либо настроить метод, чтобы он не возвращал логическое значение, если это лучше соответствует вашим потребностям. Надеюсь, это поможет?
Карл
1
Нет проблем @feleciagenet, я добавил хранение и проверку результата метода в примеры Swift и ObjectiveC.
Карл
34

Я только что создал подкласс UILabel специально для таких случаев использования. Вы можете легко добавить несколько ссылок и определить для них разные обработчики. Также поддерживается выделение нажатой ссылки при касании для обратной связи. Пожалуйста, обратитесь к https://github.com/null09264/FRHyperLabel .

В вашем случае код может выглядеть так:

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

Образец скриншота (в этом случае обработчик настроен на выдачу предупреждения вместо открытия URL)

facedancer

Цзинхань Ван
источник
если предположим, что мой текст похож на этот, этот морф был сгенерирован с помощью Face Dancer, перейдите в представление Click to Face Dancer в магазине приложений Face Dancer. здесь у меня есть 3 Face Dancer, это не
сработало
1
В этом случае, пожалуйста, используйте API - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; вместо этого. Пожалуйста, обратитесь к readme на странице GitHub.
Цзинхань Ван
1
FRHyperLabel, кажется, больше не работает. Внутри "characterIndexForPoint:" всегда возвращается -1 (не найдено).
Джон Пан
У меня не работает многострочный лейбл. Обнаружение символов неверно. 15-символьная строка ссылки кликабельна только для некоторых первых символов, другие символы ничего не делают
Accid Bright
27

Незначительное улучшение решения ujell: если вы используете NSURL вместо NSString, вы можете использовать любой URL (например, пользовательские URL)

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;

Радоваться, веселиться!

Ганс Один
источник
21

Свифт 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
Билл Чан
источник
Этот ответ отлично работает как есть. Кажется, вам не нужны какие-либо раскраски или пользовательские подклассы, которые используют другие ответы.
zeroimpl
19

У меня тоже было подобное требование, сначала я использовал UILabel, а потом понял, что UITextView лучше. Я заставил UITextView вести себя как UILabel, отключив взаимодействие и прокрутку, и создал метод категории для NSMutableAttributedStringустановки ссылки на текст, такой же, как у Карла (+1 за это), это моя версия obj c

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

Вы можете использовать делегат ниже, чтобы обработать действие

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)url inRange:(NSRange)characterRange
{
    // do the task
    return YES;
}
anoop4real
источник
1
Насколько я могу сказать, установка NSForegroundColorAttributeNameв диапазоне, где NSLinkAttributeNameприменяется, не работает. Независимо от того, linkTextAttributesчто UITextViewприменяются вместо. У NSForegroundColorAttributeNameтебя работает?
Дима
Вы уверены, что вы тоже не настроены linkTextAttributesна то же самое? или возможно tintColor? Можете ли вы сделать так, чтобы 2 ссылки отображались разными цветами в одном и том же текстовом представлении?
Дима
1
Вот рабочий код NSRange range = [self.text rangeOfString: textToFind options: NSCaseInsensitiveSearch]; if (range.location! = NSNotFound) {NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString: self.text]; [строка addAttribute: NSLinkAttributeName значение: диапазон URL: диапазон]; [string addAttribute: NSForegroundColorAttributeName значение: [UIColor blueColor] range: range]; self.text = @ ""; self.attributedText = string; }
Носов Павел
16

Используйте UITextView, он поддерживает интерактивные ссылки. Создайте приписанную строку, используя следующий код

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

Затем установите текст UITextView следующим образом

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

                                 NSUnderlineColorAttributeName: [UIColor blueColor],

                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

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

Убедитесь, что вы включили «Выбираемое» поведение UITextView в XIB.

Нитиш Джордж
источник
15
Я думаю, что это лучшее решение! Примечание о включении Selectableважно!
LunaCodeGirl
Это не подчеркивает ссылку для меня (iOS 7, 8). Мне нужно было использовать NSUnderlineStyleAttributeName: [NSNumber numberWithInt: NSUnderlineStyleSingle]
prewett
1
возможность выбора - самая важная и не интуитивная информация!
Николас Массарт,
13

Суть моего вопроса заключалась в том, что я хотел иметь возможность создавать кликабельные ссылки в текстовых представлениях / полях / метках без необходимости писать собственный код для манипулирования текстом и добавления ссылок. Я хотел, чтобы это управлялось данными.

Я наконец понял, как это сделать. Проблема в том, что IB не соблюдает встроенные ссылки.

Кроме того, версия для iOS NSAttributedStringне позволяет инициализировать приписанную строку из файла RTF. Версия OS X из NSAttributedString действительно есть инициализатор , который принимает файл в формате RTF в качестве входных данных.

NSAttributedString соответствует протоколу NSCoding, поэтому вы можете преобразовать его в / из NSData

Я создал инструмент командной строки OS X, который принимает файл RTF в качестве входных данных и выводит файл с расширением .data, который содержит NSData из NSCoding. Затем я помещаю файл .data в свой проект и добавляю пару строк кода, который загружает текст в представление. Код выглядит так (этот проект был в 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
}

Для приложений, которые используют много форматированного текста, я создаю правило сборки, которое сообщает Xcode, что все файлы .rtf в данной папке являются исходными, а файлы .data - выходными. После этого я просто добавляю файлы .rtf в назначенный каталог (или редактирую существующие файлы), и процесс сборки выясняет, что они новые / обновленные, запускает инструмент командной строки и копирует файлы в комплект приложения. Работает красиво.

Я написал сообщение в блоге, которое ссылается на пример (Swift) проекта, демонстрирующего эту технику. Вы можете видеть это здесь:

Создание интерактивных URL-адресов в UITextField, которые открываются в вашем приложении

Дункан С
источник
11

Пример Swift 3 для обнаружения действий при атрибуции текстовых нажатий

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
}

Также вы можете добавить любое действие, которое хотите, с shouldInteractWith URLпомощью метода UITextFieldDelegate.

Ура !!

Акила Васала
источник
7

Быстрый ответ - использование UITextView вместо UILabel. Вам нужно включить Selectableи отключить Editable.

Затем отключите индикаторы прокрутки и отскоки.

Скриншот

Скриншот

Мое решение с использованием NSMutableAttributedStringстроки 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;
Доди Рахмат Викаксоно
источник
Это. Я смог прочитать RTF-файл из моего комплекта ресурсов, преобразовать его NSAttributedString, установить в качестве attributedTextмоего UITextViewи гиперссылки просто работают! Было бы много работы, чтобы найти диапазон каждой гиперссылки и настроить ее с помощью атрибутов.
Николас Миари
6

Я написал метод, который добавляет ссылку (linkString) к строке (fullString) с определенным 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;
}

Вы должны назвать это так:

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];
Денис Кутлубаев
источник
Это кликабельно, но не открывает ссылку или что-то еще. это просто щелкает как кнопка, которая ничего не делает.
Reza.Ab
5

Мне нужно было продолжать использовать чистый UILabel, так называемый это из моего распознавателя касаний (это основано на ответе malex здесь: Индекс символов в точке касания для 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];
                                          }
                                      }];
Мостовский
источник
Это было очень полезно, мне не удалось получить индексы для символов в последней строке. Ваш код имеет +100 на textContainer при инициализации CGSize, что не имеет большого смысла для меня, но это помогло.
Blueether
4

Обновить:

На мой вопрос было 2 ключевых части:

  1. Как создать ссылку, в которой текст, отображаемый для кликабельной ссылки, отличается от действительной ссылки, которая вызывается:
  2. Как настроить ссылки без использования специального кода для установки атрибутов в тексте.

Оказывается, в iOS 7 добавлена ​​возможность загрузки атрибутивного текста из NSData.

Я создал собственный подкласс, UITextViewкоторый использует @IBInspectableатрибут и позволяет загружать содержимое из файла RTF непосредственно в IB. Вы просто вводите имя файла в IB, а пользовательский класс делает все остальное.

Вот подробности:

В iOS 7 NSAttributedStringполучил метод initWithData:options:documentAttributes:error:. Этот метод позволяет загрузить NSAttributedString из объекта NSData. Вы можете сначала загрузить файл RTF в NSData, а затем использовать initWithData:options:documentAttributes:error:для загрузки этих NSData в ваше текстовое представление. (Обратите внимание, что есть также метод, initWithFileURL:options:documentAttributes:error:который будет загружать атрибутированную строку непосредственно из файла, но этот метод устарел в iOS 9. Безопаснее использовать метод initWithData:options:documentAttributes:error:, который не устарел.

Я хотел метод, который позволял бы мне устанавливать кликабельные ссылки в моих текстовых представлениях без необходимости создавать какой-либо код, специфичный для ссылок, которые я использовал.

Решение, которое я придумал, состояло в том, чтобы создать собственный подкласс UITextView, который я вызываю, RTF_UITextViewи присвоить ему @IBInspectableсвойство с именем RTF_Filename. Добавление @IBInspectableатрибута к свойству заставляет Интерфейсный Разработчик выставить это свойство в «Инспекторе Атрибутов». Затем вы можете установить это значение из IB без специального кода.

Я также добавил @IBDesignableатрибут в свой пользовательский класс. @IBDesignableАтрибут сообщает Xcode , что он должен установить запущенную копию пользовательского класса представления в строитель интерфейс , так что вы можете увидеть его в графическом дисплее вашего зрения иерархии. () К сожалению, для этого класса @IBDesignableсвойство выглядит нечетким. Это сработало, когда я впервые добавил его, но затем я удалил текстовое содержимое моего текстового представления, и кликабельные ссылки в моем представлении исчезли, и я не смог их вернуть.)

Код для моего RTF_UITextViewочень прост. Помимо добавления @IBDesignableатрибута и RTF_Filenameсвойства с @IBInspectableатрибутом, я добавил didSet()метод к RTF_Filenameсвойству. didSet()Метод вызывается каждый раз , когда значение RTF_Filenameсвойства изменяется. Код для didSet()метода довольно прост:

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

Обратите внимание, что если свойство @IBDesignable не позволяет надежно предварительно просматривать стилизованный текст в Интерфейсном конструкторе, то может быть лучше установить приведенный выше код как расширение UITextView, а не как пользовательский подкласс. Таким образом, вы можете использовать его в любом текстовом представлении, не меняя текстовое представление на пользовательский класс.

Смотрите мой другой ответ, если вам нужно поддерживать версии iOS до iOS 7.

Вы можете скачать пример проекта, который включает этот новый класс, из gitHub:

Демонстрационный проект DatesInSwift на Github

Дункан С
источник
3

Просто найдите решение без кода для UITextView: введите описание изображения здесь

Включите Обнаружение-> Параметры ссылок, URL, а также адрес электронной почты будут обнаружены и кликабельны!

Билл Чан
источник
3
Это делает ссылки кликабельными. Я хочу, чтобы читаемый текст содержал ссылку за ним. Смотрите пример в моем оригинальном вопросе.
Дункан C
Да, мой ответ относится только к случаю, когда ссылка совпадает с текстом. Если бы ссылка была другой вещью, я бы следовал за ответом @ ujell.
Билл Чан
3
Мой вопрос был очень конкретно о кликабельном тексте, который отображает что-то кроме URL. Вы только взглянули на вопрос?
Дункан C
1
не предназначался для других, но, конечно, это то, что я искал в стеке ... способ сделать ссылки в моем приложении чата интерактивными. Бинго я нашел эту статью ... спасибо! Хотелось бы, чтобы xcode позволил включить твиттер и хеш-тег.
MizAkita
Это работает даже с пользовательским текстом, вставленным из необработанной ссылки. Не забудьте выбрать Поведение -> Выбор и Обнаружение -> Ссылки.
КРЛБСК
3

Swift версия:

    // 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
ioopl
источник
3

Используйте UITextView и установите dataDetectorTypes для Link.

как это:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

Если вы хотите определить ссылку, номер телефона, адрес и т. Д. Затем

testTextView.dataDetectorTypes = .all
Адарш Г.Дж.
источник
3
Нет. Это позволяет вам делать ссылки кликабельными. Мой вопрос относится к тому, чтобы сделать произвольный текст, такой как «кликни здесь», кликабельным, а не URL-адрес, какhttp://somedomain/someurl?param=value
Duncan C
2

Быстрое добавление к оригинальному описанию Дункана С в отношении поведения IB. Он пишет: «Сделать гиперссылки кликабельными в UITextView довольно просто. Вы просто устанавливаете флажок« обнаруживать ссылки »в представлении в IB, и он обнаруживает ссылки http и превращает их в гиперссылки».

Мой опыт (по крайней мере, в xcode 7) заключается в том, что вам также нужно отключить поведение «Редактируемый», чтобы URL-адреса были обнаружены и кликабельны.

sakumatto
источник
2

Если у вас возникли проблемы с тем, что @Karl Nosworthy и @esilver предоставили выше, я обновил расширение NSMutableAttributedString до его версии 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

Если вы хотите использовать NSLinkAttributeName в UITextView, то вы можете рассмотреть возможность использования библиотеки AttributedTextView. Это подкласс UITextView, который очень легко справляется с ними. Для получения дополнительной информации см .: https://github.com/evermeer/AttributedTextView

Вы можете заставить любую часть текста взаимодействовать следующим образом (где textView1 - это UITextView IBoutlet):

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) 

А для обработки хэштегов и упоминаний вы можете использовать такой код:

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

если вы хотите активную подстроку в вашем UITextView, то вы можете использовать мой расширенный TextView ... он короткий и простой. Вы можете редактировать его, как хотите.

результат: введите описание изображения здесь

код: https://github.com/marekmand/ActiveSubstringTextView

Марек Мандуч
источник
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;

КЛЮЧЕВЫЕ МОМЕНТЫ:

  • Убедитесь, что вы включили «Выбираемое» поведение UITextView в XIB.
  • Убедитесь, что вы отключили «редактируемое» поведение UITextView в XIB.
Шашанк Шарма
источник