许多应用程序都有文本,文本中是圆角矩形的web超链接,当我点击它们时,UIWebView就会打开。让我困惑的是,他们经常有自定义链接,例如,如果单词以#开头,它也是可点击的,应用程序通过打开另一个视图来响应。我该怎么做呢?是否可以用UILabel或者我需要UITextView或者其他什么?
当前回答
我很难处理这件事…带有链接的UILabel在带属性的文本上…这只是一个头痛,所以我最终使用ZSWTappableLabel。
其他回答
下面是超链接UILabel的示例代码: 来源:http://sickprogrammersarea.blogspot.in/2014/03/adding-links-to-uilabel.html
#import "ViewController.h"
#import "TTTAttributedLabel.h"
@interface ViewController ()
@end
@implementation ViewController
{
UITextField *loc;
TTTAttributedLabel *data;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(5, 20, 80, 25) ];
[lbl setText:@"Text:"];
[lbl setFont:[UIFont fontWithName:@"Verdana" size:16]];
[lbl setTextColor:[UIColor grayColor]];
loc=[[UITextField alloc] initWithFrame:CGRectMake(4, 20, 300, 30)];
//loc.backgroundColor = [UIColor grayColor];
loc.borderStyle=UITextBorderStyleRoundedRect;
loc.clearButtonMode=UITextFieldViewModeWhileEditing;
//[loc setText:@"Enter Location"];
loc.clearsOnInsertion = YES;
loc.leftView=lbl;
loc.leftViewMode=UITextFieldViewModeAlways;
[loc setDelegate:self];
[self.view addSubview:loc];
[loc setRightViewMode:UITextFieldViewModeAlways];
CGRect frameimg = CGRectMake(110, 70, 70,30);
UIButton *srchButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
srchButton.frame=frameimg;
[srchButton setTitle:@"Go" forState:UIControlStateNormal];
[srchButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
srchButton.backgroundColor=[UIColor clearColor];
[srchButton addTarget:self action:@selector(go:) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:srchButton];
data = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(5, 120,self.view.frame.size.width,200) ];
[data setFont:[UIFont fontWithName:@"Verdana" size:16]];
[data setTextColor:[UIColor blackColor]];
data.numberOfLines=0;
data.delegate = self;
data.enabledTextCheckingTypes=NSTextCheckingTypeLink|NSTextCheckingTypePhoneNumber;
[self.view addSubview:data];
}
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url
{
NSString *val=[[NSString alloc]initWithFormat:@"%@",url];
if ([[url scheme] hasPrefix:@"mailto"]) {
NSLog(@" mail URL Selected : %@",url);
MFMailComposeViewController *comp=[[MFMailComposeViewController alloc]init];
[comp setMailComposeDelegate:self];
if([MFMailComposeViewController canSendMail])
{
NSString *recp=[[val substringToIndex:[val length]] substringFromIndex:7];
NSLog(@"Recept : %@",recp);
[comp setToRecipients:[NSArray arrayWithObjects:recp, nil]];
[comp setSubject:@"From my app"];
[comp setMessageBody:@"Hello bro" isHTML:NO];
[comp setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentViewController:comp animated:YES completion:nil];
}
}
else{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:val]];
}
}
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
if(error)
{
UIAlertView *alrt=[[UIAlertView alloc]initWithTitle:@"Erorr" message:@"Some error occureed" delegate:nil cancelButtonTitle:@"" otherButtonTitles:nil, nil];
[alrt show];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
[self dismissViewControllerAnimated:YES completion:nil];
}
}
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithPhoneNumber:(NSString *)phoneNumber
{
NSLog(@"Phone Number Selected : %@",phoneNumber);
UIDevice *device = [UIDevice currentDevice];
if ([[device model] isEqualToString:@"iPhone"] ) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel:%@",phoneNumber]]];
} else {
UIAlertView *Notpermitted=[[UIAlertView alloc] initWithTitle:@"Alert" message:@"Your device doesn't support this feature." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[Notpermitted show];
}
}
-(void)go:(id)sender
{
[data setText:loc.text];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"Reached");
[loc resignFirstResponder];
}
这个通用方法也可以!
func didTapAttributedTextInLabel(gesture: UITapGestureRecognizer, inRange targetRange: NSRange) -> Bool {
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: CGSize.zero)
guard let strAttributedText = self.attributedText else {
return false
}
let textStorage = NSTextStorage(attributedString: strAttributedText)
// Configure layoutManager and textStorage
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
// Configure textContainer
textContainer.lineFragmentPadding = Constants.lineFragmentPadding
textContainer.lineBreakMode = self.lineBreakMode
textContainer.maximumNumberOfLines = self.numberOfLines
let labelSize = self.bounds.size
textContainer.size = CGSize(width: labelSize.width, height: CGFloat.greatestFiniteMagnitude)
// Find the tapped character location and compare it to the specified range
let locationOfTouchInLabel = gesture.location(in: self)
let xCordLocationOfTouchInTextContainer = locationOfTouchInLabel.x
let yCordLocationOfTouchInTextContainer = locationOfTouchInLabel.y
let locOfTouch = CGPoint(x: xCordLocationOfTouchInTextContainer ,
y: yCordLocationOfTouchInTextContainer)
let indexOfCharacter = layoutManager.characterIndex(for: locOfTouch, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
guard let strLabel = text else {
return false
}
let charCountOfLabel = strLabel.count
if indexOfCharacter < (charCountOfLabel - 1) {
return NSLocationInRange(indexOfCharacter, targetRange)
} else {
return false
}
}
你可以用
let text = yourLabel.text
let termsRange = (text as NSString).range(of: fullString)
if yourLabel.didTapAttributedTextInLabel(gesture: UITapGestureRecognizer, inRange: termsRange) {
showCorrespondingViewController()
}
从iOS 15开始,SwiftUI内置支持Markdown标记语言,因此Markdown中的文本:
Text("You can [click this link](https://www.example.com) to visit the website.")
或者作为一个使用SwiftUI的最简单的例子,你可以这样做:
HStack() {
Text("Open the")
.foregroundColor(.black)
Link(destination: URL(string: "https://www.example.com/TOS.html")!) {
Text("link")
.foregroundColor(.blue)
.underline()
}
Text("in browser")
.foregroundColor(.black)
}
我们使用来自zekel的UITapGestureRecognizer类别的方便解决方案。 它使用了NSTextContainer,就像这个问题的许多答案一样。
但是,这将返回错误的字符索引。显然是因为NSTextContainer缺少关于字体样式的信息,正如这些其他帖子所指出的:
https://stackoverflow.com/a/34238382/2439941 https://stackoverflow.com/a/47358270/2439941
后改变:
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];
To:
// Apply the font of the label to the attributed text:
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:label.attributedText];
NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
paragraphStyle.alignment = self.label.textAlignment;
[attributedText addAttributes:@{NSFontAttributeName: label.font, NSParagraphStyleAttributeName: paragraphStyle}
range:NSMakeRange(0, label.attributedText.string.length)];
// Init with attributed text from label:
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
结果明显更好,点击区域现在正确地从目标字符串的第一个字符开始。但最后一个字符仍然返回NO。我们期望这与我们的目标字符串具有将字体权重设置为UIFontWeightSemibold的属性有关。而上面的代码改进应用标签。整个字符串上的字体,它有一个规则的权重。
为了解决这个问题,我们进一步改进了上面的代码片段,通过遍历所有属性范围,以支持文本中的多种字体样式:
// According to https://stackoverflow.com/a/47358270/2439941 it's required to apply the paragraph style and font of the UILabel.
// However, the attributed string might contain font formatting as well, e.g. to emphasize a word in a different font style.
// Therefor copy all attributes:
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:label.attributedText];
[label.attributedText enumerateAttributesInRange:NSMakeRange(0, label.attributedText.length)
options:0
usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
// Add each attribute:
[attributedText addAttributes:attrs
range:range];
// In case the attributes of this range do NOT contain a font specifier, apply the font from the UILabel:
if (![attrs objectForKey:NSFontAttributeName]) {
[attributedText addAttributes:@{ NSFontAttributeName : label.font }
range:range];
}
}];
// Init the storage with the font attributed text:
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
现在,该方法为半粗体字符串范围内的每个字符返回YES,这是预期的结果。
NSString *string = name;
NSError *error = NULL;
NSDataDetector *detector =
[NSDataDetector dataDetectorWithTypes:(NSTextCheckingTypes)NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber
error:&error];
NSArray *matches = [detector matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches)
{
if (([match resultType] == NSTextCheckingTypePhoneNumber))
{
NSString *phoneNumber = [match phoneNumber];
NSLog(@" Phone Number is :%@",phoneNumber);
label.enabledTextCheckingTypes = NSTextCheckingTypePhoneNumber;
}
if(([match resultType] == NSTextCheckingTypeLink))
{
NSURL *email = [match URL];
NSLog(@"Email is :%@",email);
label.enabledTextCheckingTypes = NSTextCheckingTypeLink;
}
if (([match resultType] == NSTextCheckingTypeLink))
{
NSURL *url = [match URL];
NSLog(@"URL is :%@",url);
label.enabledTextCheckingTypes = NSTextCheckingTypeLink;
}
}
label.text =name;
}
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- Swift:声明一个空字典
- 我如何用javascript编程点击链接?
- 在成功提交我的应用程序后,“太多符号文件”
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- CFNetwork SSLHandshake iOS 9失败
- 请求失败:不可接受的内容类型:文本/html使用AFNetworking 2.0
- 缺少推荐的图标文件-该包不包含iPhone / iPod Touch的应用程序图标,像素为“120x120”,png格式
- 以编程方式创建segue