NSAttributedString içinde tıklanabilir bir bağlantıyı nasıl oluşturabilirim?


200

A'da köprüleri tıklanabilir hale getirmek önemsizdir UITextView. IB'deki görünümde "bağlantıları algıla" onay kutusunu ayarlamanız yeterlidir ve HTTP bağlantılarını algılar ve bunları köprülere dönüştürür.

Ancak bu yine de kullanıcının gördüğü şeyin "ham" bağlantı olduğu anlamına gelir. RTF dosyaları ve HTML'nin her ikisi de "arkasında" bir bağlantıyla kullanıcı tarafından okunabilir bir dize oluşturmanıza olanak tanır.

Bu atfedilen bir metin görünümünde metin yüklemek kolaydır (ya da UILabelya da UITextFieldbu konuda,.) O atfedilen metin bir bağlantı içerir Ancak, tıklanabilir değildir.

Kullanıcı okunabilir metin bir tıklanabilir hale getirmek bir yolu var mı UITextView, UILabelyoksa UITextField?

İşaretleme SO'da farklıdır, ancak genel fikir burada. Ne istiyorum böyle metin:

Bu morph Face Dancer ile oluşturuldu , App Store'da görüntülemek için tıklayın.

Alabileceğim tek şey şudur:

Bu morph Yüz Dansçısı ile oluşturuldu , Uygulama mağazasında görüntülemek için http://example.com/facedancer tıklayın .


Bu örneği deneyin .. IFTweetLabel Umut yardımcı olur ..
Vidhyanand


İyi iş bir göz kırpışından 100K geçiyor. 100K kulübe hoş geldiniz. Hak ettin!
vacawama

@vacawama, bekle, bu ne zaman oldu? En son baktığımda ≈98k'daydım! (100k kulübün bir üyesi olarak SO swag aldığınız hakkında söylentiler duyuyorum?)
Duncan C

Sorularda +5'ten +10'a kadar oy değiştirdiler, bu yüzden 800 kadar oyunuz olsaydı bir flaşta +4000 net olacaktı. Hala 100 bin yağma bekliyorum (Nisan ayında geçti).
Yağma

Yanıtlar:


156

NSMutableAttributedString kullanın .

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

Düzenle :

Bu doğrudan soru ile ilgili değildir, sadece açıklığa kavuşturmak içindir UITextFieldve UILabelaçılış URL'lerini desteklemez. UILabelBağlantılarla kullanmak istiyorsanız TTTAttributedLabel'i kontrol edebilirsiniz .

Ayrıca belirlesin dataDetectorTypes, aramalarınızdan değerini UITextViewetmek UIDataDetectorTypeLinkveya UIDataDetectorTypeAlltıklandığında açık URL'ler. Veya yorumlarda önerildiği gibi temsilci yöntemini kullanabilirsiniz.


8
Evet, çalışıyor, sadece bir UITextView içine koyun ve delege yöntemini geçersiz kılın: - (BOOL) textView: (UITextView *) textView gerekirInInractWithURL: (NSURL *) url inRange: (NSRange) characterRange
Yunus Nedim Mehel

Bu bir UILabel'da çalışmaz - alana dokunduğunuzda hiçbir şey olmaz.
Jack BeNimble

7
@saboehnke Yani link tıklandığında bir yöntem çağırmak? öyleyse delege yöntemini uygulayın, öznitelik olarak bir kukla URL verin ve yönteminizi çağırın- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
ujell

2
Nasıl çalıştığını bilmiyorum. Özniteliğin değeri türünde olmalıdır NSURL. ----[str addAttribute: NSLinkAttributeName value: [NSURL URLWithString:@"http://www.google.com"] range: NSMakeRange(0, str.length)];
Nirav Dangi

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

143

Bunu gerçekten yararlı buldum, ancak birkaç yerde yapmam gerekiyordu, bu yüzden yaklaşımımı basit bir uzantıda tamamladım NSMutableAttributedString:

Hızlı 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
    }
}

Hızlı 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
   }
}

Örnek kullanım:

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

if linkWasSet {
    // adjust more attributedString properties
}

Objective-C

Aynı şeyi saf bir Objective-C projesinde yapmak için bir gereksinime çarptım, işte Objective-C kategorisi.

@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

Örnek kullanım:

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

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

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

NSTextField'ın Davranış özniteliğinin Seçilebilir olarak ayarlandığından emin olun. Xcode NSTextField davranış özniteliği


Bunun hızlı bir kullanım / uygulama örneği çok takdir edilecektir.
ioopl

3
@ioop. Yukarıdaki orijinal gönderiye çok küçük bir örnek ekledim, umarım yardımcı olur.
Karl Nosworthy

7
Bu doğru çalıştı. Sadece bağlantı tıklanabilir olması için UITextView seçilebilir yapmak gerektiğini söylemek istiyorum
lujop

1
@ felecia genet, hem Objective C hem de Swift uygulamalarında yöntem, bir eşleşmenin ve sonuç kümesinin gerçekleşip gerçekleşmediğini belirtmek için bir boole sonucunu döndürür. Gördüğünüz hata, bu sonucu yakalamamanızdır - ki bu da iyidir. Bu sonucu yerel bir değişkene atayarak yakalayabilir veya ihtiyaçlarınıza daha uygunsa boole değerini döndürmesini durdurmak için yöntemi ayarlayabilirsiniz. Umarım bu yardımcı olur?
Karl Nosworthy

1
Sorun yok @feleciagenet, hem Swift hem de ObjectiveC örneklerine yöntem sonucunun depolanmasını ve kontrol edilmesini ekledim.
Karl Nosworthy

34

Bu tür kullanım durumlarını özel olarak ele almak için bir UILabel alt sınıfı oluşturdum. Kolayca birden çok bağlantı ekleyebilir ve bunlar için farklı işleyiciler tanımlayabilirsiniz. Ayrıca, dokunma geribildirimi için aşağıya dokunduğunuzda basılan bağlantıyı vurgulamayı da destekler. Bakınız https://github.com/null09264/FRHyperLabel .

Sizin durumunuzda, kod şöyle olabilir:

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

Örnek Ekran Görüntüsü (işleyici, bu durumda bir URL açmak yerine bir uyarı görüntüleyecek şekilde ayarlanmıştır)

facedancer


varsayalım metnim böyle ise Bu morph Yüz Dansçı ile oluşturuldu, App Store Yüz Dansçı yüz yüze dansçı görünümü tıklayın. işte ben bunun için çalışma değildi 3 Yüz Dansçı yaşıyorum
MANCHIKANTI KRISHNAKISHORE

1
Bu durumda lütfen - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; bunun yerine API'yi kullanın. Lütfen github sayfasındaki benioku dosyasına bakın.
Jinghan Wang

1
FRHyperLabel artık çalışmıyor gibi görünüyor. "CharacterIndexForPoint:" içinde her zaman -1 (bulunamadı) döndürür.
John Pang

Çok satırlı etiket için benim için çalışmıyor. Karakterlerin algılanması yanlış. 15 karakterlik bağlantı dizesi yalnızca bazı ilk karakterlerde tıklanabilir, diğer karakterler hiçbir şey yapmaz
Accid Bright

27

Ujell'in çözümünde küçük iyileştirme: NSString yerine NSURL kullanıyorsanız, herhangi bir URL'yi kullanabilirsiniz (ör. Özel URL'ler)

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;

İyi eğlenceler!


21

Hızlı 4:

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

yourTextView.attributedText = attributedString

Hızlı 3.1:

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

yourTextView.attributedText = attributedString

Bu cevap olduğu gibi mükemmel çalışıyor. Diğer cevapların kullandığı renklendirme veya özel alt sınıflara ihtiyaç duymuyorsunuz.
zeroimpl

19

Ben de benzer bir gereksinim vardı, başlangıçta UILabel kullandım ve sonra UITextView daha iyi olduğunu fark ettim. Etkileşimi ve kaydırmayı devre dışı bırakarak UITextView'in UILabel gibi davranmasını sağladım ve NSMutableAttributedStringKarl'ın yaptığı şeyle aynı metne bağlantı ayarlamak için bir kategori yöntemi yaptım (bunun için +1) bu benim obj c sürümüm

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

eylemi işlemek için aşağıdaki temsilciyi kullanabilirsiniz

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

1
Uygulanabilir NSForegroundColorAttributeNamebir aralıkta ayarın NSLinkAttributeNameçalışmadığını söyleyebildiğim kadarıyla . Hayır, ne önemi linkTextAttributesait UITextViewyerine uygulanır. Sizin için NSForegroundColorAttributeNameçalışıyor mu ?
Dima

linkTextAttributesAynı şeyi yapmadığınızdan emin misiniz ? ya da belki tintColor? Aynı metin görünümünde 2 bağlantıyı farklı renklerde gösterebiliyor musunuz?
Dima

1
İşte çalışma kodu NSRange range = [self.text rangeOfString: textToFind options: NSCaseInsensitiveSearch]; if (range.location! = NSNotFound) {NSMutableAttributedString * string = [[NSMutableAttributedString ayır] initWithString: self.text]; [string addAttribute: NSLinkAttributeName değeri: url aralığı: aralık]; [string addAttribute: NSForegroundColorAttributeName değeri: [UIColor blueColor] aralık: aralık]; self.text = @ ""; self.attributedText = string; }
Nosov Pavel

16

Tıklanabilir Bağlantıları destekleyen UITextView kullanın. Aşağıdaki kodu kullanarak ilişkilendirilmiş dize oluşturun

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

Ardından UITextView metnini aşağıdaki gibi ayarlayın

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

                                 NSUnderlineColorAttributeName: [UIColor blueColor],

                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

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

XIB'de UITextView "Seçilebilir" davranışını etkinleştirdiğinizden emin olun.


15
Bence bu en iyi çözüm! Etkinleştirme Selectableile ilgili not önemlidir!
LunaCodeGirl

Bu benim için bağlantının altını çizmedi (iOS 7, 8). NSUnderlineStyleAttributeName kullanmam gerekiyordu: [NSNumber numberWithInt: NSUnderlineStyleSingle]
prewett

1
seçilebilir yapmak en önemli ve sezgisel olmayan bilgidir!
Nicolas Massart

13

Sorumun kalbi, metni değiştirmek ve bağlantıları eklemek için özel kod yazmak zorunda kalmadan metin görünümlerinde / alanlarında / etiketlerinde tıklanabilir bağlantılar oluşturmak istememdi. Veriye dayalı olmasını istedim.

Sonunda nasıl yapılacağını anladım. Mesele, IB'nin gömülü bağlantıları onurlandırmamasıdır.

Ayrıca, iOS sürümü, NSAttributedStringbir RTF dosyasından ilişkilendirilmiş bir dizeyi başlatmanıza izin vermez. OS X sürümü NSAttributedString yapar giriş olarak bir RTF dosyası alır bir başlatıcı var.

NSAttributedString NSCoding protokolüne uygundur, böylece NSData'ya / NSData'dan dönüştürebilirsiniz

Bir RTF dosyasını girdi olarak alan ve NSCoding NSData içeren .data uzantılı bir dosya çıktısı bir OS X komut satırı aracı oluşturdum. Daha sonra .data dosyasını projeme koydum ve metni görünüme yükleyen birkaç satır kod ekledim. Kod şöyle görünür (bu proje Swift'teydi):

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

Çok fazla biçimlendirilmiş metin kullanan uygulamalar için, Xcode'a belirli bir klasördeki tüm .rtf dosyalarının kaynak ve .data dosyalarının çıktı olduğunu söyleyen bir oluşturma kuralı oluştururum. Bunu yaptıktan sonra, sadece belirtilen dizine .rtf dosyaları eklerim (veya varolan dosyaları düzenlerim) ve derleme işlemi yeni / güncel olduklarını, komut satırı aracını çalıştırır ve dosyaları uygulama paketine kopyalar. Güzel çalışıyor.

Tekniği gösteren örnek (Swift) projesine bağlantı veren bir blog yazısı yazdım. Burada görebilirsiniz:

Uygulamanızda açılan bir UITextField öğesinde tıklanabilir URL'ler oluşturma


11

İlişkilendirilmiş metin dokunuşlarındaki eylemleri algılamak için Swift 3 örneği

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
}

Bilge gibi shouldInteractWith URLUITextFieldDelegate yöntemiyle istediğiniz eylemleri ekleyebilirsiniz .

Alkış !!


7

Hızlı yanıt, UILabel yerine UITextView kullanıyor. Etkinleştirmeniz Selectableve devre dışı bırakmanız gerekir Editable.

Ardından kaydırma göstergelerini ve sıçramaları devre dışı bırakın.

Ekran Görüntüsü

Ekran Görüntüsü

NSMutableAttributedStringHtml dizesinden kullanarak benim çözümNSHTMLTextDocumentType

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;

Bu. Kaynak paketimden bir RTF dosyasını okuyabildim, dönüştürdüm , benim ve köprülerim NSAttributedStringolarak ayarladım ! Her köprünün aralığını bulmak ve öznitelikleri kullanarak kurmak çok iş olurdu. attributedTextUITextView
Nicolas Miari

6

Belirli bir url (urlString) ile bir dizeye (fullString) bir bağlantı (linkString) ekleyen bir yöntem yazdım:

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

Buna şöyle demelisin:

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

Tıklanabilir ancak bağlantıyı veya başka bir şeyi açmaz. sadece hiçbir şey yapmayan bir düğme gibi tıklar.
Reza.Ab

5

Benim musluk tanıyıcı denilen saf bir UILabel kullanmaya devam etmek gerekiyordu (bu malex burada yanıt dayanmaktadır: UILabel için temas noktasında karakter dizini )

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

Bu oldukça yardımcı oldu, son satırdaki karakterlerden dizin alamadım. Kodunuz CGSize'i başlatırken textContainer üzerinde +100 değerine sahip, bu bana çok mantıklı değil, ancak hile yaptı.
blueether

4

Güncelleme:

Sorumun 2 anahtar kısmı vardı:

  1. Tıklanabilir bağlantı için gösterilen metnin, çağrılan gerçek bağlantıdan farklı olduğu bir bağlantı nasıl yapılır:
  2. Metin üzerindeki öznitelikleri ayarlamak için özel kod kullanmak zorunda kalmadan bağlantılar nasıl ayarlanır.

Görünüşe göre iOS 7, ilişkilendirilen metni yükleme yeteneğini ekledi NSData.

Özel bir alt sınıf oluşturdum UITextView.@IBInspectableÖznitelikten ve içeriği doğrudan IB'de bir RTF dosyasından yüklemenizi sağlayan . Dosya adını IB'ye yazmanız yeterlidir ve özel sınıf gerisini halleder.

İşte detaylar:

İOS 7'de NSAttributedStringyöntemi kazandı initWithData:options:documentAttributes:error:. Bu yöntem, bir NSData nesnesinden bir NSAttributedString yüklemenize izin verir. Önce bir RTF dosyasını NSData'ya initWithData:options:documentAttributes:error:yükleyebilir , ardından bu NSData'yı metin görünümünüze yüklemek için kullanabilirsiniz . ( initWithFileURL:options:documentAttributes:error:İlişkilendirilmiş bir dizeyi doğrudan bir dosyadan yükleyecek bir yöntem olduğunu, ancak bu yöntemin iOS 9'da kullanımdan initWithData:options:documentAttributes:error:kaldırıldığını unutmayın. Kullanımdan kaldırılmayan yöntemi kullanmak daha güvenlidir .

Kullandığım bağlantılara özgü herhangi bir kod oluşturmak zorunda kalmadan metin görünümlerime tıklanabilir bağlantılar yüklememe izin veren bir yöntem istedim.

Ben geldi çözüm UITextView I çağrı özel bir alt sınıf oluşturmak RTF_UITextViewve @IBInspectabledenilen bir özellik vermek oldu RTF_Filename. Ekleme@IBInspectableBir özelliğe özellik Interface Builder'ın bu özelliği "Özellik Denetçisi" nde göstermesine neden olur. Daha sonra bu değeri IB özel koduyla ayarlayabilirsiniz.

Özel sınıfıma da bir @IBDesignableözellik ekledim . @IBDesignableNitelik, görünüm hiyerarşi grafiksel ekranda görebilirsiniz nedenle Arayüz Oluşturucu içine özel görünüm sınıfının çalışan kopyasını yüklemek gerektiğini Xcode söyler. () Ne yazık ki, bu sınıf için, @IBDesignablemülkiyet lapa lapa gibi görünüyor. İlk eklediğimde işe yaradı, ancak daha sonra metin görünümümün düz metin içeriğini sildim ve görünümümdeki tıklanabilir bağlantılar kayboldu ve bunları geri alamadım.)

Benim için kod RTF_UITextViewçok basit. @IBDesignableÖzniteliği ve özniteliği olan bir RTF_Filenameözelliği eklemeye ek olarak, özelliğe @IBInspectablebir didSet()yöntem ekledim RTF_Filename. didSet()Yöntem herhangi bir zaman değerini çağrılanRTF_Filename değiştiğinde . didSet()Yöntemin kodu oldukça basittir:

@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 özelliği, stilli metninizi Interface builder'da önizlemenize güvenilir bir şekilde izin vermiyorsa, yukarıdaki kodu özel bir alt sınıf yerine UITextView uzantısı olarak ayarlamak daha iyi olabilir. Bu şekilde, metin görünümünü özel sınıfa değiştirmek zorunda kalmadan herhangi bir metin görünümünde kullanabilirsiniz.

İOS 7'den önceki iOS sürümlerini desteklemeniz gerekiyorsa diğer cevabımı görün.

Bu yeni sınıfı içeren örnek bir projeyi gitHub'dan indirebilirsiniz:

DatesInSwift demo projesi Github


3

Sadece UITextView için kodsuz bir çözüm bulun: resim açıklamasını buraya girin

Algılamayı etkinleştir -> Bağlantılar seçenekleri, URL ve ayrıca e-posta algılanır ve tıklanabilir!


3
Bu, bağlantıları tıklanabilir hale getirir. Arkasında bir bağlantı bulunan, kullanıcı tarafından okunabilir bir metin istiyorum. Orijinal sorumdaki örneğe bakın.
Duncan C

Evet, cevabım yalnızca bağlantının metinle aynı olması durumunda geçerlidir. Bağlantı başka bir şeyse, @ ujell'in cevabını takip ederim.
Bill Chan

3
Sorum, özellikle URL'den başka bir şey görüntüleyen tıklanabilir metinle ilgiliydi. Soruya bir bakıştan daha fazlasını yapmadın, değil mi?
Duncan C

1
başkalarının amaca hizmet etmedi ama şüphesiz bu aramaya geldiğim şey ... sohbet uygulamamdaki bağlantıları tıklanabilir hale getirmenin bir yolu. Bingo Bu yazıyı buldum ... teşekkürler! Dilek xcode twitter ve hash etiketi etkinleştirme sağlar.
MizAkita

Bu, ham bağlantıdan alınan özel metinle bile çalışır. Davranış -> Seçilebilir ve Algılama -> Bağlantılar'ı seçmeyi unutmayın.
krlbsk

3

Hızlı Sürüm:

    // 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 kullanın ve Link için dataDetectorTypes ayarlayın.

bunun gibi:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

Bağlantı, telefon numarası, adres vb. Tespit etmek istiyorsanız.

testTextView.dataDetectorTypes = .all

3
Hayır. Bu yalnızca bağlantıları tıklanabilir yapmanıza olanak tanır. Benim sorum, "burayı tıklayın" gibi rastgele bir metnin tıklanabilir olması gibi bir URL'ye özgüdürhttp://somedomain/someurl?param=value
Duncan C

2

Duncan C'nin IB davranışına ilişkin orijinal açıklamasına hızlı bir ek. Şöyle yazıyor: "Bir UITextView içinde köprüleri tıklanabilir yapmak önemsizdir. Sadece IB'deki görünümde" bağlantıları algıla "onay kutusunu ayarlamanız yeterlidir ve http bağlantılarını algılar ve köprüler haline getirir."

Deneyimlerim (en azından xcode 7'de), tespit edilecek ve tıklanabilir URL'ler için "Düzenlenebilir" davranışını da kaldırmanız gerektiğidir.


2

@Karl Nosworthy ve @esilver'in yukarıda belirttiği sorunlarla ilgili sorun yaşıyorsanız, NSMutableAttributedString uzantısını Swift 4 sürümüne güncelledim.

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

Bir UITextView içinde NSLinkAttributeName kullanmak istiyorsanız, AttributedTextView kitaplığını kullanmayı düşünebilirsiniz. Bunları idare etmeyi çok kolaylaştıran bir UITextView alt sınıfıdır. Daha fazla bilgi için bkz. Https://github.com/evermeer/AttributedTextView

Metnin herhangi bir bölümünün bu şekilde etkileşime girmesini sağlayabilirsiniz (burada textView1 bir UITextView IBoutlet'tir):

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) 

Ve hashtag'leri ve sözleri işlemek için aşağıdaki gibi bir kod kullanabilirsiniz:

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;

ANAHTAR NOKTALARI:

  • XIB'de UITextView "Seçilebilir" davranışını etkinleştirdiğinizden emin olun.
  • XIB'de UITextView "Düzenlenebilir" davranışını devre dışı bıraktığınızdan emin olun.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.