gpt4 book ai didi

ios - 在 UILabel 的 NSAttributedString 中创建可点击的 "links"?

转载 作者:行者123 更新时间:2023-11-30 12:14:32 29 4
gpt4 key购买 nike

许多应用程序都有文本,并且在该文本中是圆角矩形中的 Web 超链接。当我单击它们时,UIWebView 打开。让我困惑的是,它们经常有自定义链接,例如,如果单词以 # 开头,它也是可单击的,并且应用程序通过打开另一个 View 来响应。我怎样才能做到这一点?是否可以使用 UILabel 或者我需要 UITextView 或其他东西?

最佳答案

一般来说,如果我们希望 UILabel 显示的文本中有可点击的链接,我们需要解决两个独立的任务:

  1. 更改部分文本的外观,使其看起来像链接
  2. 检测并处理对链接的触摸(打开网址是一种特殊情况)

第一个很简单。从 iOS 6 开始 UILabel 支持显示属性字符串。您需要做的就是创建并配置 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;

就是这样!上面的代码使 UILabel 显示带有 linkString

现在我们应该检测对此链接的触摸。这个想法是捕获 UILabel 内的所有点击,并确定点击的位置是否距离链接足够近。为了捕捉触摸,我们可以向标签添加点击手势识别器。确保为标签启用 userInteraction,默认情况下它是关闭的:

label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]];

现在是最复杂的事情:查明点击是否位于链接显示的位置,而不是标签的任何其他部分。如果我们有单行 UILabel,则可以通过对显示链接的区域边界进行硬编码来相对容易地解决此任务,但让我们更优雅地解决此问题,对于一般情况 - 多行 UILabel,无需对链接布局有初步了解。

其中一种方法是使用 iOS 7 中引入的 Text Kit API 功能:

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

将创建和配置的 NSLayoutManager、NSTextContainer 和 NSTextStorage 实例保存在类的属性中(很可能是 UIViewController 的后代) - 我们将在其他方法中需要它们。

现在,每次标签更改其框架时,都会更新 textContainer 的大小:

- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.textContainer.size = self.label.bounds.size;
}

最后,检测点击是否正好在链接上:

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

关于ios - 在 UILabel 的 NSAttributedString 中创建可点击的 "links"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45594346/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com