Secara umum, jika kita ingin memiliki tautan yang dapat diklik dalam teks yang ditampilkan oleh UILabel, kita perlu menyelesaikan dua tugas independen:
- Mengubah tampilan sebagian teks agar terlihat seperti tautan
- Mendeteksi dan menangani sentuhan pada tautan (membuka URL adalah kasus khusus)
Yang pertama mudah. Mulai dari iOS 6 UILabel mendukung tampilan string yang dikaitkan. Yang perlu Anda lakukan adalah membuat dan mengonfigurasikan instance NSMutableAttributedString:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"String with a link" attributes:nil];
NSRange linkRange = NSMakeRange(14, 4); // for the word "link" in the string above
NSDictionary *linkAttributes = @{ NSForegroundColorAttributeName : [UIColor colorWithRed:0.05 green:0.4 blue:0.65 alpha:1.0],
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle) };
[attributedString setAttributes:linkAttributes range:linkRange];
// Assign attributedText to UILabel
label.attributedText = attributedString;
Itu dia! Kode di atas membuat UILabel untuk menampilkan String dengan tautan
Sekarang kita harus mendeteksi sentuhan pada tautan ini. Idenya adalah menangkap semua ketukan di dalam UILabel dan mencari tahu apakah lokasi keran cukup dekat dengan tautan. Untuk menangkap sentuhan, kita dapat menambahkan pengenal isyarat ketuk pada label. Pastikan untuk mengaktifkan interaksi Pengguna untuk label, ini dimatikan secara default:
label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]];
Sekarang hal yang paling canggih: cari tahu apakah keran ada di tempat tautan ditampilkan dan bukan pada bagian label lainnya. Jika kami memiliki UILabel baris tunggal, tugas ini dapat diselesaikan dengan relatif mudah dengan melakukan hardcoding batas area tempat tautan ditampilkan, tetapi mari kita selesaikan masalah ini dengan lebih elegan dan untuk kasus umum - multiline UILabel tanpa pengetahuan awal tentang tata letak tautan.
Salah satu pendekatan adalah menggunakan kemampuan API Kit Teks yang diperkenalkan di iOS 7:
// Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
// Configure layoutManager and textStorage
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
// Configure textContainer
textContainer.lineFragmentPadding = 0.0;
textContainer.lineBreakMode = label.lineBreakMode;
textContainer.maximumNumberOfLines = label.numberOfLines;
Simpan contoh NSLayoutManager, NSTextContainer, dan NSTextStorage yang dibuat dan dikonfigurasikan di properti di kelas Anda (kemungkinan besar keturunan UIViewController) - kami akan membutuhkannya dalam metode lain.
Sekarang, setiap kali label mengubah bingkainya, perbarui ukuran textContainer:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.textContainer.size = self.label.bounds.size;
}
Dan akhirnya, deteksi apakah keran itu ada di tautan:
- (void)handleTapOnLabel:(UITapGestureRecognizer *)tapGesture
{
CGPoint locationOfTouchInLabel = [tapGesture locationInView:tapGesture.view];
CGSize labelSize = tapGesture.view.bounds.size;
CGRect textBoundingBox = [self.layoutManager usedRectForTextContainer:self.textContainer];
CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
locationOfTouchInLabel.y - textContainerOffset.y);
NSInteger indexOfCharacter = [self.layoutManager characterIndexForPoint:locationOfTouchInTextContainer
inTextContainer:self.textContainer
fractionOfDistanceBetweenInsertionPoints:nil];
NSRange linkRange = NSMakeRange(14, 4); // it's better to save the range somewhere when it was originally used for marking link in attributed string
if (NSLocationInRange(indexOfCharacter, linkRange)) {
// Open an URL, or handle the tap on the link in any other way
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://stackoverflow.com/"]];
}
}
Swift 4
solusi yang berfungsi penuh . MenggunakanUITextView
tetapi membuatnya berperilaku sepertiUILabel
. Saya mencoba solusinya di sini, dan gagal mendapatkan deteksi tautan yang akurat.