Genel olarak, UILabel tarafından görüntülenen metinde tıklanabilir bir bağlantıya sahip olmak istiyorsak, iki bağımsız görevi çözmemiz gerekir:
- Bağlantıya benzemek için metnin bir bölümünün görünümünü değiştirme
- Bağlantıdaki dokunuşları algılama ve işleme (URL açmak belirli bir durumdur)
İlki kolaydır. İOS 6'dan başlayarak UILabel, ilişkilendirilmiş dizelerin görüntülenmesini destekler. Tek yapmanız gereken bir NSMutableAttributedString örneği oluşturmak ve yapılandırmaktır:
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;
Bu kadar! Yukarıdaki kod UILabel'i String ile bir link görüntüleyecek şekilde yapar
Şimdi bu bağlantıdaki dokunuşları tespit etmeliyiz. Fikir, UILabel içindeki tüm muslukları yakalamak ve musluğun konumunun bağlantıya yeterince yakın olup olmadığını anlamaktır. Dokunuşları yakalamak için etikete dokunma hareketi tanıyıcı ekleyebiliriz. Etiket için userInteraction'ı etkinleştirdiğinizden emin olun, varsayılan olarak kapalıdır:
label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]];
Şimdi en sofistike şeyler: musluğun etiketin başka herhangi bir yerinde değil, bağlantının görüntülendiği yerde olup olmadığını bulmak. Tek çizgili UILabel'ımız olsaydı, bu görev bağlantının görüntülendiği alan sınırlarını zor kodlayarak nispeten kolay bir şekilde çözülebilir, ancak bu sorunu daha zarif ve genel durum için - bağlantı düzeni hakkında ön bilgi olmadan çok satırlı UILabel çözelim.
Yaklaşımlardan biri, iOS 7'de tanıtılan Metin Kiti API'sinin özelliklerini kullanmaktır:
// 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;
Oluşturulan ve yapılandırılan NSLayoutManager, NSTextContainer ve NSTextStorage örneklerini sınıfınızdaki özelliklere kaydedin (büyük olasılıkla UIViewController'ın soyundan) - diğer yöntemlerde bunlara ihtiyacımız olacak.
Şimdi, etiket çerçevesini her değiştirdiğinde metni güncelleyin
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.textContainer.size = self.label.bounds.size;
}
Ve son olarak, musluğun tam olarak bağlantıda olup olmadığını tespit edin:
- (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
. KullanırUITextView
ama bir gibi davranmasını sağlarUILabel
. Burada çözümleri denedim ve doğru bağlantı algılamayı başaramadım.