Em geral, se quisermos ter um link clicável no texto exibido pelo UILabel, precisaremos resolver duas tarefas independentes:
- Alterando a aparência de uma parte do texto para parecer um link
- Detectando e manipulando toques no link (abrir um URL é um caso específico)
O primeiro é fácil. A partir do iOS 6, o UILabel suporta a exibição de strings atribuídas. Tudo que você precisa fazer é criar e configurar uma instância do 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;
É isso aí! O código acima faz com que o UILabel exiba String com um link
Agora devemos detectar toques neste link. A idéia é capturar todos os toques no UILabel e descobrir se o local do toque estava próximo o suficiente do link. Para capturar toques, podemos adicionar o reconhecedor de gestos ao toque. Certifique-se de ativar userInteraction para o rótulo, pois está desativado por padrão:
label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]];
Agora, o mais sofisticado: descobrir se a torneira estava onde o link é exibido e não em qualquer outra parte do rótulo. Se tivéssemos o UILabel de linha única, essa tarefa poderia ser resolvida de maneira relativamente fácil, codificando os limites da área em que o link é exibido, mas vamos resolver esse problema de maneira mais elegante e, para casos gerais - UILabel de várias linhas sem conhecimento preliminar sobre o layout do link.
Uma das abordagens é usar os recursos da API do kit de texto introduzidos no 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;
Salve instâncias criadas e configuradas do NSLayoutManager, NSTextContainer e NSTextStorage nas propriedades da sua classe (provavelmente descendente do UIViewController) - precisaremos delas em outros métodos.
Agora, sempre que o rótulo alterar seu quadro, atualize o tamanho do textContainer:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.textContainer.size = self.label.bounds.size;
}
E, finalmente, detecte se a torneira estava exatamente no link:
- (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
solução totalmente funcional . Ele usa,UITextView
mas faz com que se comporte como umUILabel
. Tentei as soluções aqui e não obtive a detecção precisa do link.