Як я можу зробити посилання, яке можна натискати, у NSAttributedString?


200

Тривіально робити гіперпосилання, які можна натискати в UITextView. Ви просто встановите прапорець "Виявити посилання" на поданні в IB, і він виявить HTTP-посилання та перетворює їх у гіперпосилання.

Однак це все ще означає, що те, що бачить користувач, є "сирим" посиланням. Файли RTF та HTML дозволяють налаштувати читабельний рядок із посиланням "позаду".

Це легко встановити приписуваний текст в текстовому вигляді (або UILabelчи UITextField, по цьому питанню.) Тим НЕ менше, коли надавав текст містить посилання, які не клікабельно.

Чи є спосіб зробити текст, прочитаний користувачем, для натискання в UITextView, UILabelабо UITextField?

Розмітка відрізняється на SO, але тут загальна ідея. Мені хочеться такий текст:

Цей морф створено за допомогою Face Dancer , Клацніть для перегляду в магазині додатків.

Єдине, що я можу отримати:

Цей морф створений за допомогою Face Dancer. Клацніть на http://example.com/facedancer, щоб переглянути його у магазині додатків.


Спробуйте цей зразок .. IFTweetLabel Сподіваюся, що це допомагає ..
Vidhyanand


Хороша робота, що дме мимо 100 К, підморгнувши на очі. Ласкаво просимо в клуб 100К. Заслуженим!
vacawama

@vacawama, почекай, коли це сталося? Я був у ≈98к востаннє, коли я дивився! (Я чую чутки про те, що ти отримуєш
Duncan C

Вони змінили обгрунтування на питання від +5 до +10, тож якщо у вас було 800 посилань, миттєво вимкнете +4000. Я все ще чекаю на 100k свог (перетнув у квітні). Щось про зміну постачальників
свагів

Відповіді:


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-адреси при натисканні. Або ви можете скористатися методом делегата, як запропоновано в коментарях.


7
Так, він працює, просто помістіть його в метод UITextView і перезазначте делегат: - (BOOL) textView: (UITextView *) textView shouldInteractWithURL: (NSURL *) url inRange: (NSRange) characterRange
Yunus 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
Ахмед Навар

142

Я вважаю це дійсно корисним, але мені потрібно було це зробити у небагатьох місцях, тож я пояснив свій підхід простим розширенням до 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
    }
}

Швидкий 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.

@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, метод повертає бульний результат, щоб вказати, чи відбувся збіг та отриманий набір. Помилка, яку ви бачите, полягає в тому, що ви не фіксуєте цей результат - це добре. Ви можете або захопити цей результат, призначивши його локальній змінній, або скоригувавши метод, щоб зупинити повернення булевого значення, якщо це краще відповідає вашим потребам. Я сподіваюся, що це допомагає?
Karl Nosworthy

1
Немає проблем @feleciagenet, я додав збереження та перевірку результату методу як у приклади Swift, так і в ObjectiveC.
Karl Nosworthy

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-адреси в цьому випадку)

стикається


якщо припустимо, що мій текст виглядає таким чином. Цей морф був створений за допомогою Face Dancer, клацніть для перегляду танцюриста Face у магазині додатків Face Dancer. тут у мене є 3 Face Dancer, це не працювало для цього
MANCHIKANTI KRISHNAKISHORE

1
У цьому випадку скористайтеся API - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; замість цього. Будь ласка, зверніться до readme на сторінці github.
Jinghan Wang

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

Швидкий 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;
}

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: діапазон]; [рядок addAttribute: NSForegroundColorAttributeName значення: [UIColor blueColor] діапазон: діапазон]; self.text = @ ""; self.attributedText = рядок; }
Носов Павло

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 відповідає протоколу NSC кодування, тому ви можете конвертувати його в / з 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.

Потім вимкніть індикатори прокрутки та відмов.

Екран постріл

Екран постріл

Моє рішення з використанням NSMutableAttributedStringHTML-рядкаNSHTMLTextDocumentType

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і гіперпосилання просто працюють! Було б багато роботи, щоб знайти діапазон кожного гіперпосилання та встановити його за допомогою атрибутів.
Nicolas Miari

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

Його можна натискати, але він не відкриває посилання або щось інше. він просто клацає як кнопка, яка нічого не робить.
Реза.Аб

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, що для мене не має великого сенсу, але це зробило трюк.
блютер

4

Оновлення:

У моєму питанні було дві ключові частини:

  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 атрибуту до властивості змушує Інтерфейс Builder викрити цю властивість у "Ревізорі атрибутів". Потім ви можете встановити це значення з 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-адресу. Ви не розглядали питання, чи не так?
Duncan C

1
не слугував іншим цілям, але, безумовно, це те, що я прийшов шукати стек ... спосіб зробити посилання в моєму додатку для чату. Бінго, я знайшов цю статтю ... дякую! Бажаний xcode дозволить увімкнути щебетати та хеш-теги.
MizAkita

Це працює навіть із нестандартним текстом, який складається з необробленого посилання. Не забудьте вибрати Поведінка -> Вибір та виявлення -> Посилання.
Крлбськ

3

Швидка версія:

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

Використовуйте UITextView і встановлюйте dataDetectorTypes для посилання.

подобається це:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

Якщо ви хочете виявити посилання, номер телефону, адресу тощо

testTextView.dataDetectorTypes = .all

3
Ні. Це дозволяє лише зробити посилання доступними для натискання. Моє запитання стосується того, щоб зробити довільний текст на зразок "натисніть сюди", а не URL-адресу, наприкладhttp://somedomain/someurl?param=value
Duncan C

2

Швидке доповнення до оригінального опису Duncan C щодо поведінки IB. Він пише: "Тривіально зробити так, щоб гіперпосилання можна було натискати в UITextView. Ви просто встановите прапорець" Виявити посилання "на поданні в IB, і він виявляє http-посилання та перетворює їх у гіперпосилання".

Мій досвід (принаймні в xcode 7) полягає в тому, що ви також повинні знімати клавішу "Редагована" поведінка, щоб URL-адреси були виявлені та натиснуті.


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
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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.