โดยทั่วไปถ้าเราต้องการให้มีลิงค์ที่สามารถคลิกได้ในข้อความที่แสดงโดย UILabel เราจะต้องแก้ไขงานอิสระสองอย่าง:
- การเปลี่ยนลักษณะที่ปรากฏของส่วนของข้อความให้มีลักษณะเหมือนลิงก์
- การตรวจจับและจัดการสัมผัสบนลิงค์ (การเปิด URL เป็นกรณีพิเศษ)
คนแรกนั้นง่าย การเริ่มต้นจาก 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 แสดงสตริงด้วยลิงก์
ตอนนี้เราควรตรวจจับการสัมผัสที่ลิงค์นี้ แนวคิดก็คือการจับก๊อกทั้งหมดภายใน UILabel และดูว่าตำแหน่งของก๊อกนั้นใกล้กับลิงก์มากพอหรือไม่ เพื่อจับสัมผัสเราสามารถเพิ่มตัวจดจำท่าทางการแตะลงในฉลาก ตรวจสอบให้แน่ใจว่าได้เปิดใช้งาน userInteraction สำหรับป้ายกำกับมันถูกปิดโดยค่าเริ่มต้น:
label.userInteractionEnabled = YES;
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapOnLabel:)]];
ตอนนี้สิ่งที่ซับซ้อนที่สุด: ค้นหาว่าการแตะอยู่ที่การแสดงลิงก์หรือไม่และไม่ได้อยู่ในส่วนอื่น ๆ ของฉลาก หากเรามี UILabel ที่มีเส้นเดียวงานนี้สามารถแก้ไขได้ค่อนข้างง่ายโดยการเขียนโค้ดขอบเขตพื้นที่ที่ลิงก์ปรากฏ แต่ให้แก้ปัญหานี้ได้ดีกว่าและสำหรับกรณีทั่วไป - multiline UILabel โดยไม่มีความรู้เบื้องต้นเกี่ยวกับโครงร่างลิงค์
หนึ่งในวิธีการคือการใช้ความสามารถของ Text Kit API ที่แนะนำใน 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;
บันทึกอินสแตนซ์ที่สร้างและกำหนดค่าของ 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/"]];
}
}
Swift 4
แก้ปัญหาการทำงานอย่างสมบูรณ์ มันใช้แต่ทำให้มันทำตัวเหมือนUITextView
UILabel
ฉันลองวิธีแก้ปัญหาที่นี่และไม่สามารถตรวจสอบลิงก์ที่ถูกต้องได้