Bagaimana saya bisa membuat tautan yang dapat diklik dalam NSAttributedString?

200

Itu sepele untuk membuat hyperlink yang dapat diklik dalam UITextView. Anda cukup mengatur kotak centang "deteksi tautan" pada tampilan di IB, dan mendeteksi tautan HTTP dan mengubahnya menjadi hyperlink.

Namun, itu masih berarti bahwa apa yang dilihat pengguna adalah tautan "mentah". File RTF dan HTML memungkinkan Anda mengatur string yang dapat dibaca pengguna dengan tautan "di belakang".

Mudah untuk memasang teks yang dikaitkan ke tampilan teks (atau a UILabelatau UITextField, dalam hal ini.) Namun, ketika teks yang dikaitkan itu menyertakan tautan, itu tidak dapat diklik.

Apakah ada cara untuk membuat teks yang dapat dibaca pengguna dapat diklik dalam UITextView, UILabelatau UITextField?

Markupnya berbeda pada SO, tapi di sini ada ide umum. Yang saya inginkan adalah teks seperti ini:

Morf ini dihasilkan dengan Penari Wajah , Klik untuk melihat di app store.

Satu-satunya yang bisa saya dapatkan adalah ini:

Morf ini dihasilkan dengan Penari Wajah, Klik pada http://example.com/facedancer untuk melihat di app store.

Duncan C
sumber
Coba sampel ini .. IFTweetLabel Semoga ini membantu ..
Vidhyanand
Pekerjaan bagus menembus 100 ribu dalam sekejap mata. Selamat datang di klub 100K. Sangat layak!
vacawama
@vacawama, tunggu, kapan itu terjadi? Saya berada di ≈98k terakhir kali saya melihat! (Saya mendengar desas-desus bahwa Anda mendapatkan barang curian SO sebagai anggota klub 100k?)
Duncan C
Mereka mengubah upvotes pada pertanyaan dari +5 menjadi +10, jadi jika Anda memiliki 800 upvotes, Anda akan mendapatkan +4000 dalam sekejap. Saya masih menunggu 100k barang curian (menyeberang pada bulan April). Sesuatu tentang mengganti vendor barang curian ...
vacawama

Jawaban:

156

Gunakan NSMutableAttributedString .

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

Edit :

Ini bukan langsung tentang pertanyaan tetapi hanya untuk mengklarifikasi, UITextFielddan UILabeltidak mendukung membuka URL. Jika Anda ingin menggunakan UILabeltautan, Anda dapat memeriksa TTTAttributedLabel .

Anda juga harus menetapkan dataDetectorTypesnilai Anda UITextViewke UIDataDetectorTypeLinkatau UIDataDetectorTypeAlluntuk membuka URL ketika diklik. Atau Anda dapat menggunakan metode delegasi seperti yang disarankan dalam komentar.

ujell
sumber
7
Ya, itu berfungsi, cukup letakkan di dalam metode UITextView dan timpa delegasi: - (BOOL) textView: (UITextView *) textView harusInteractWithURL: (NSURL *) url inRange: (NSRange) characterRange
Yunus Nedim Mehel
Ini tidak berfungsi dalam label UIL - tidak ada yang terjadi saat Anda mengetuk bidang.
Jack BeNimble
7
@saboehnke maksud Anda memanggil metode saat tautan diklik? jika demikian terapkan metode delegate, berikan url dummy sebagai atribut dan panggil metode Anda di- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
ujell
2
Saya tidak tahu cara kerjanya. Nilai atribut harus berupa tipe NSURL. ----[str addAttribute: NSLinkAttributeName value: [NSURL URLWithString:@"http://www.google.com"] range: NSMakeRange(0, str.length)];
Nirav Dangi
1
@NiravDangi dariNSAttributedString.h UIKIT_EXTERN NSString * const NSLinkAttributeName NS_AVAILABLE(10_0, 7_0); // NSURL (preferred) or NSString
Ahmed Nawar
143

Saya menemukan ini sangat berguna tetapi saya perlu melakukannya di beberapa tempat jadi saya telah membungkus pendekatan saya dalam ekstensi sederhana untuk NSMutableAttributedString:

Cepat 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
    }
}

Cepat 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
   }
}

Contoh penggunaan:

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

if linkWasSet {
    // adjust more attributedString properties
}

Objektif-C

Saya baru saja mencapai persyaratan untuk melakukan hal yang sama dalam proyek Objective-C murni, jadi inilah kategori 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

Contoh penggunaan:

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

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

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

Pastikan bahwa atribut Perilaku NSTextField ditetapkan sebagai Dapat Dipilih. Atribut perilaku Xcode NSTextField

Karl Nosworthy
sumber
Contoh penggunaan / implementasi cepat ini akan sangat dihargai.
ioopl
3
@ op. Saya telah menambahkan contoh yang sangat kecil ke posting asli di atas, semoga membantu.
Karl Nosworthy
7
Ini bekerja dengan benar. Hanya ingin mengatakan bahwa Anda perlu membuat UITextView Anda dapat dipilih agar tautannya dapat diklik
lujop
1
@felecia genet, baik dalam implementasi Objective C dan Swift, metode mengembalikan hasil boolean untuk menunjukkan apakah kecocokan dan hasil yang dihasilkan terjadi. Kesalahan yang Anda lihat adalah karena Anda tidak menangkap hasil itu - yang baik-baik saja. Anda bisa menangkap hasil itu dengan menugaskannya ke variabel lokal atau menyesuaikan metode untuk menghentikannya mengembalikan nilai boolean jika itu lebih sesuai dengan kebutuhan Anda. Saya harap itu membantu?
Karl Nosworthy
1
Tidak masalah @feleciagenet, saya telah menambahkan penyimpanan dan pengecekan hasil metode ke contoh Swift dan ObjectiveC.
Karl Nosworthy
34

Saya baru saja membuat subkelas UILabel untuk secara khusus menangani kasus penggunaan tersebut. Anda dapat menambahkan banyak tautan dengan mudah dan menentukan penangan yang berbeda untuknya. Ini juga mendukung menyoroti tautan yang ditekan ketika Anda menyentuh untuk umpan balik sentuhan. Silakan merujuk ke https://github.com/null09264/FRHyperLabel .

Dalam kasus Anda, kodenya mungkin seperti ini:

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

Contoh Screenshot (pawang diatur untuk memunculkan peringatan alih-alih membuka url dalam kasus ini)

yang dihadapi

Jinghan Wang
sumber
jika anggaplah teks saya seperti ini. Morf ini dihasilkan dengan Penari Wajah, Klik untuk melihat Penari Wajah di app store Penari Wajah. di sini saya memiliki 3 Penari Wajah, itu tidak berfungsi untuk itu
MANCHIKANTI KRISHNAKISHORE
1
Dalam hal ini, silakan gunakan API - (void)setLinkForRange:(NSRange)range withLinkHandler:(void(^)(FRHyperLabel *label, NSRange selectedRange))handler; sebagai gantinya. Silakan merujuk ke readme di halaman github.
Jinghan Wang 3-15
1
FRHyperLabel sepertinya tidak berfungsi lagi. Di dalam "characterIndexForPoint:", selalu kembali -1 (tidak ditemukan).
John Pang
Tidak bekerja untuk saya untuk label multiline. Deteksi karakter salah. String 15-karakter dapat diklik hanya pada beberapa karakter pertama, karakter lain tidak melakukan apa pun
Accid Bright
27

Perbaikan kecil untuk solusi ujell: Jika Anda menggunakan NSURL alih-alih NSString, Anda dapat menggunakan URL apa pun (mis. Url khusus)

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;

Selamat bersenang-senang!

Hans One
sumber
21

Swift 4:

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

yourTextView.attributedText = attributedString

Swift 3.1:

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

yourTextView.attributedText = attributedString
Bill Chan
sumber
Jawaban ini berfungsi dengan baik apa adanya. Sepertinya tidak membutuhkan pewarna atau subkelas khusus yang digunakan jawaban lain.
zeroimpl
19

Saya juga memiliki persyaratan yang sama, awalnya saya menggunakan UILabel dan kemudian saya menyadari bahwa UITextView lebih baik. Saya membuat UITextView berperilaku seperti UILabel dengan menonaktifkan interaksi dan menggulir dan membuat metode kategori untuk NSMutableAttributedStringmengatur tautan ke teks sama seperti apa yang telah dilakukan Karl (+1 untuk itu) ini adalah versi objektif saya

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

Anda dapat menggunakan delegasi di bawah ini untuk menangani tindakan

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)url inRange:(NSRange)characterRange
{
    // do the task
    return YES;
}
anoop4real
sumber
1
Sejauh yang saya tahu pengaturan NSForegroundColorAttributeNamedalam kisaran di mana NSLinkAttributeNamediterapkan tidak bekerja. Tidak peduli apa, yang linkTextAttributesdari UITextViewditerapkan sebagai gantinya. Apakah NSForegroundColorAttributeNameberhasil untuk Anda?
Dima
Apakah Anda yakin tidak juga mengatur linkTextAttributeshal yang sama? atau mungkin tintColor? Apakah Anda dapat membuat 2 tautan muncul dalam warna berbeda di tampilan teks yang sama?
Dima
1
Berikut ini adalah kode kerja NSRange range = [self.text rangeOfString: textToFind options: NSCaseInsensitiveSearch]; if (range.location! = NSNotFound) {NSMutableAttributedString * string = [[Alokasi NSMutableAttributedString] initWithString: self.text]; [string addAttribute: NSLinkAttributeName value: url range: range]; [string addAttribute: NSForegroundColorAttributeName nilai: [UIColor blueColor] range: range]; self.text = @ ""; self.attributedText = string; }
Nosov Pavel
16

Gunakan UITextView mendukung Tautan yang dapat diklik. Buat string yang dikaitkan menggunakan kode berikut

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

Kemudian atur teks UITextView sebagai berikut

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

                                 NSUnderlineColorAttributeName: [UIColor blueColor],

                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

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

Pastikan Anda mengaktifkan perilaku "Selectable" dari UITextView di XIB.

Nitheesh George
sumber
15
Saya pikir ini adalah solusi terbaik! Catatan tentang mengaktifkan Selectableitu penting!
LunaCodeGirl
Ini tidak menggarisbawahi tautan untuk saya (iOS 7, 8). Saya perlu menggunakan NSUnderlineStyleAttributeName: [NSNumber numberWithInt: NSUnderlineStyleSingle]
prewett
1
menjadikannya dapat dipilih adalah informasi yang paling penting dan tidak intuitif!
Nicolas Massart
13

Inti dari pertanyaan saya adalah bahwa saya ingin dapat membuat tautan yang dapat diklik dalam tampilan teks / bidang / label tanpa harus menulis kode khusus untuk memanipulasi teks dan menambahkan tautan. Saya ingin ini berbasis data.

Saya akhirnya menemukan cara melakukannya. Masalahnya adalah bahwa IB tidak menghormati tautan yang disematkan.

Selain itu, versi iOS NSAttributedStringtidak memungkinkan Anda menginisialisasi string yang dikaitkan dari file RTF. Versi OS X NSAttributedString memang memiliki initializer yang mengambil file RTF sebagai input.

NSAttributedString sesuai dengan protokol NSCoding, sehingga Anda dapat mengubahnya ke / dari NSData

Saya membuat alat baris perintah OS X yang mengambil file RTF sebagai input dan menghasilkan file dengan ekstensi .data yang berisi NSData dari NSCoding. Saya kemudian memasukkan file data ke proyek saya dan menambahkan beberapa baris kode yang memuat teks ke dalam tampilan. Kode ini terlihat seperti ini (proyek ini di 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
}

Untuk aplikasi yang menggunakan banyak teks berformat, saya membuat aturan build yang memberi tahu Xcode bahwa semua file .rtf dalam folder yang diberikan adalah sumber dan file .data adalah output. Setelah saya melakukannya, saya cukup menambahkan file .rtf ke direktori yang ditunjuk, (atau mengedit file yang ada) dan proses build mengetahui bahwa file tersebut baru / diperbarui, menjalankan alat baris perintah, dan menyalin file ke dalam bundel aplikasi. Itu bekerja dengan indah.

Saya menulis posting blog yang terhubung ke proyek sampel (Swift) yang menunjukkan teknik ini. Anda bisa melihatnya di sini:

Membuat URL yang dapat diklik di UITextField yang terbuka di aplikasi Anda

Duncan C
sumber
11

Swift 3 contoh untuk mendeteksi tindakan pada keran teks yang dikaitkan

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
}

Seperti bijaksana Anda dapat menambahkan tindakan yang Anda inginkan dengan shouldInteractWith URLmetode UITextFieldDelegate.

Bersulang!!

Akila Wasala
sumber
7

Jawaban cepat menggunakan UITextView, bukan UILabel. Anda harus mengaktifkan Selectabledan menonaktifkan Editable.

Kemudian nonaktifkan indikator gulir dan memantul.

Tangkapan Layar

Tangkapan Layar

Solusi saya menggunakan NSMutableAttributedStringdari string 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;
Dody Rachmat Wicaksono
sumber
Ini. Saya dapat membaca file RTF dari bundel sumber daya saya, mengkonversinya menjadi NSAttributedString, menjadikannya sebagai attributedTextmilik saya UITextViewdan hyperlink berfungsi! Ini akan menjadi banyak pekerjaan untuk menemukan jangkauan setiap hyperlink dan mengaturnya menggunakan atribut.
Nicolas Miari
6

Saya telah menulis sebuah metode, yang menambahkan tautan (linkString) ke string (fullString) dengan url tertentu (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;
}

Anda harus menyebutnya seperti ini:

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];
Denis Kutlubaev
sumber
Bisa diklik tetapi tidak membuka tautan atau apa pun. itu hanya klik seperti tombol yang tidak melakukan apa-apa.
Reza. Pada
5

Saya harus tetap menggunakan UILabel murni, yang disebut ini dari pengenal keran saya (ini didasarkan pada respons malex di sini: Indeks karakter pada titik sentuh untuk 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];
                                          }
                                      }];
masty
sumber
Ini cukup membantu, saya tidak bisa mendapatkan indeks dari karakter di baris terakhir. Kode Anda memiliki +100 pada textContainer ketika init'ing CGSize, yang tidak masuk akal bagi saya, tetapi itu berhasil.
blueether
4

Memperbarui:

Ada 2 bagian penting dari pertanyaan saya:

  1. Cara membuat tautan di mana teks yang ditampilkan untuk tautan yang dapat diklik berbeda dari tautan aktual yang dipanggil:
  2. Cara mengatur tautan tanpa harus menggunakan kode khusus untuk mengatur atribut pada teks.

Ternyata iOS 7 menambahkan kemampuan untuk memuat teks yang dikaitkan dari NSData.

Saya membuat subkelas kustom UITextViewyang memanfaatkan@IBInspectable atribut dan memungkinkan Anda memuat konten dari file RTF langsung di IB. Anda cukup mengetikkan nama file ke IB dan kelas kustom melakukan sisanya.

Berikut detailnya:

Di iOS 7, NSAttributedStringdiperoleh metode initWithData:options:documentAttributes:error:. Metode itu memungkinkan Anda memuat NSAttributedString dari objek NSData. Pertama-tama Anda dapat memuat file RTF ke NSData, lalu gunakan initWithData:options:documentAttributes:error:untuk memuat NSData itu ke dalam tampilan teks Anda. (Perhatikan bahwa ada juga metode initWithFileURL:options:documentAttributes:error:yang akan memuat string yang dikaitkan langsung dari file, tetapi metode itu sudah usang di iOS 9. Lebih aman untuk menggunakan metode ini initWithData:options:documentAttributes:error:, yang tidak usang.

Saya ingin metode yang memungkinkan saya memasang tautan yang dapat diklik ke dalam tampilan teks saya tanpa harus membuat kode khusus untuk tautan yang saya gunakan.

Solusi yang saya buat adalah membuat subkelas kustom dari UITextView yang saya panggil RTF_UITextViewdan memberinya @IBInspectableproperti yang disebut RTF_Filename. Menambahkan @IBInspectableatribut ke properti menyebabkan Interface Builder memaparkan properti itu di "Atribut Inspektur." Anda kemudian dapat menetapkan nilai itu dari IB tanpa kode khusus.

Saya juga menambahkan @IBDesignableatribut ke kelas khusus saya. The @IBDesignableatribut memberitahu Xcode bahwa itu harus menginstal salinan menjalankan adat pandang kelas Anda menjadi Antarmuka pembangun sehingga Anda dapat melihatnya dalam tampilan grafis dari hierarki tampilan Anda. () Sayangnya, untuk kelas ini, @IBDesignableproperti tampaknya serpihan. Ini berfungsi ketika saya pertama kali menambahkannya, tetapi kemudian saya menghapus isi teks biasa dari tampilan teks saya dan tautan yang dapat diklik dalam tampilan saya hilang dan saya belum bisa mendapatkannya kembali.)

Kode untuk saya RTF_UITextViewsangat sederhana. Selain menambahkan @IBDesignableatribut dan RTF_Filenameproperti dengan @IBInspectableatribut, saya menambahkan didSet()metode ke RTF_Filenameproperti. The didSet()Metode dipanggil setiap saat nilai RTF_Filenameperubahan properti. Kode untuk didSet()metode ini cukup sederhana:

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

Perhatikan bahwa jika properti @IBDesignable tidak akan memungkinkan Anda untuk melihat pratinjau teks gaya Anda di pembuat antarmuka, maka mungkin lebih baik untuk mengatur kode di atas sebagai ekstensi UITextView daripada subkelas kustom. Dengan begitu Anda bisa menggunakannya dalam tampilan teks apa pun tanpa harus mengubah tampilan teks ke kelas kustom.

Lihat jawaban saya yang lain jika Anda perlu mendukung versi iOS sebelum iOS 7.

Anda dapat mengunduh proyek sampel yang menyertakan kelas baru ini dari gitHub:

Proyek demo DatesInSwift di Github

Duncan C
sumber
3

Temukan saja solusi bebas kode untuk UITextView: masukkan deskripsi gambar di sini

Aktifkan opsi Deteksi-> Tautan, URL dan juga email akan terdeteksi dan dapat diklik!

Bill Chan
sumber
3
Itu membuat tautan dapat diklik. Saya ingin memiliki teks yang dapat dibaca pengguna yang memiliki tautan di belakangnya. Lihat contoh di pertanyaan awal saya.
Duncan C
Ya, jawaban saya hanya berlaku jika tautannya sama dengan teks. Jika tautannya adalah hal lain, saya akan mengikuti jawaban @ ujell.
Bill Chan
3
Pertanyaan saya adalah secara khusus tentang teks yang dapat diklik yang menampilkan sesuatu selain URL. Anda tidak melakukan lebih dari sekadar melirik pertanyaan, bukan?
Duncan C
1
tidak melayani tujuan orang lain, tetapi tentu ini yang saya datangi untuk mencari ... cara untuk membuat tautan di aplikasi obrolan saya dapat diklik. Bingo Saya menemukan artikel ini ... terima kasih! Wish xcode akan memungkinkan untuk mengaktifkan twitter dan tag hash.
MizAkita
Ini berfungsi bahkan dengan teks khusus yang dipasang pada tautan mentah. Ingatlah untuk memilih Perilaku -> Dapat Dipilih dan Deteksi -> Tautan.
krlbsk
3

Versi 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
sumber
3

Gunakan UITextView dan atur dataDetectorTypes for Link.

seperti ini:

testTextView.editable = false 
testTextView.dataDetectorTypes = .link

Jika Anda ingin mendeteksi tautan, nomor telepon, alamat dll. Maka

testTextView.dataDetectorTypes = .all
Adarsh ​​GJ
sumber
3
Tidak. Ini hanya memungkinkan Anda membuat tautan yang dapat diklik. Pertanyaan saya khusus untuk membuat teks sewenang-wenang seperti "klik di sini" dapat diklik, bukan URL sepertihttp://somedomain/someurl?param=value
Duncan C
2

Tambahan cepat untuk deskripsi asli Duncan C vis-á-vie perilaku IB. Dia menulis: "Ini sepele untuk membuat hyperlink dapat diklik dalam UITextView. Anda cukup mengatur kotak centang" deteksi tautan "pada tampilan di IB, dan itu mendeteksi tautan http dan mengubahnya menjadi hyperlink."

Pengalaman saya (setidaknya dalam xcode 7) adalah bahwa Anda juga harus menghapus perilaku "Editable" agar url terdeteksi & diklik.

sakumatto
sumber
2

Jika Anda mengalami masalah dengan apa yang telah disediakan @Karl Nosworthy dan @esilver di atas, saya telah memperbarui ekstensi NSMutableAttributedString ke versi Swift 4-nya.

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
  }
}
Vick Swift
sumber
0

Jika Anda ingin menggunakan NSLinkAttributeName di UITextView, maka Anda dapat mempertimbangkan menggunakan pustaka AttributedTextView. Ini adalah subclass UITextView yang membuatnya sangat mudah untuk menangani ini. Untuk info lebih lanjut, lihat: https://github.com/evermeer/AttributedTextView

Anda dapat membuat bagian mana pun dari teks berinteraksi seperti ini (di mana textView1 adalah 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) 

Dan untuk menangani tagar dan sebutan Anda dapat menggunakan kode seperti ini:

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 })
    }
Edwin Vermeer
sumber
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;

POIN PENTING:

  • Pastikan Anda mengaktifkan perilaku "Selectable" dari UITextView di XIB.
  • Pastikan Anda menonaktifkan perilaku "Editable" dari UITextView di XIB.
Shashank Sharma
sumber