AttributedLabel.m 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //
  2. // AttributedLabel.m
  3. // WildFireChat
  4. //
  5. // Created by heavyrain.lee on 2018/5/15.
  6. // Copyright © 2018 WildFireChat. All rights reserved.
  7. //
  8. #import "AttributedLabel.h"
  9. #import <CoreText/CoreText.h>
  10. @interface AttributedLabel()
  11. @property(nonatomic, strong)NSMutableArray *stringArray;
  12. @property(nonatomic, strong)NSMutableArray *rangeArray;
  13. @end
  14. @implementation AttributedLabel
  15. - (void)setText:(NSString *)text {
  16. self.attributedText = [self subStr:text];
  17. self.userInteractionEnabled = YES;
  18. }
  19. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  20. UITouch *touch = [touches anyObject];
  21. NSUInteger index = [self characterIndexAtPoint:[touch locationInView:self]];
  22. for(NSValue *value in self.rangeArray) {
  23. NSRange range=[value rangeValue];
  24. if (range.location <= index && (range.location+range.length) >= index) {
  25. NSInteger i=[self.rangeArray indexOfObject:value];
  26. NSString *str = self.stringArray[i];
  27. NSLog(@"touch url %@", str);
  28. NSString *pattern =@"[0-9]{5,12}";
  29. NSPredicate*pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",pattern];
  30. BOOL isNumber = [pred evaluateWithObject:str];
  31. if (isNumber) {
  32. if ([self.attributedLabelDelegate respondsToSelector:@selector(didSelectPhoneNumber:)]) {
  33. [self.attributedLabelDelegate didSelectPhoneNumber:str];
  34. }
  35. } else {
  36. if ([self.attributedLabelDelegate respondsToSelector:@selector(didSelectUrl:)]) {
  37. [self.attributedLabelDelegate didSelectUrl:str];
  38. }
  39. }
  40. }
  41. }
  42. [super touchesBegan:touches withEvent:event];
  43. }
  44. -(NSMutableAttributedString*)subStr:(NSString *)string {
  45. if (!string) {
  46. return nil;
  47. }
  48. NSError *error;
  49. //可以识别url的正则表达式
  50. NSString *regulaStr = @"((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
  51. NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regulaStr
  52. options:NSRegularExpressionCaseInsensitive
  53. error:&error];
  54. NSArray *arrayOfAllMatches = [regex matchesInString:string options:0 range:NSMakeRange(0, [string length])];
  55. NSMutableArray *arr=[[NSMutableArray alloc]init];
  56. NSMutableArray *rangeArr=[[NSMutableArray alloc]init];
  57. self.stringArray = arr;
  58. self.rangeArray = rangeArr;
  59. for (NSTextCheckingResult *match in arrayOfAllMatches) {
  60. NSString* substringForMatch;
  61. substringForMatch = [string substringWithRange:match.range];
  62. [arr addObject:substringForMatch];
  63. [rangeArr addObject:[NSValue valueWithRange:match.range]];
  64. }
  65. NSString *pattern =@"[0-9]{5,11}";
  66. regex = [NSRegularExpression regularExpressionWithPattern:pattern
  67. options:NSRegularExpressionCaseInsensitive
  68. error:&error];
  69. arrayOfAllMatches = [regex matchesInString:string options:0 range:NSMakeRange(0, [string length])];
  70. NSMutableArray *telArr = [[NSMutableArray alloc] init];
  71. for (NSTextCheckingResult *match in arrayOfAllMatches) {
  72. NSString* substringForMatch;
  73. substringForMatch = [string substringWithRange:match.range];
  74. [arr addObject:substringForMatch];
  75. [telArr addObject:substringForMatch];
  76. [rangeArr addObject:[NSValue valueWithRange:match.range]];
  77. }
  78. NSMutableAttributedString *attributedText;
  79. attributedText=[[NSMutableAttributedString alloc]initWithString:string attributes:@{NSFontAttributeName :self.font}];
  80. for(NSValue *value in rangeArr) {
  81. NSInteger index=[rangeArr indexOfObject:value];
  82. NSRange range=[value rangeValue];
  83. [attributedText addAttribute:NSLinkAttributeName value:[NSURL URLWithString:[[arr objectAtIndex:index] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] range:range];
  84. [attributedText addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:range];
  85. }
  86. return attributedText;
  87. }
  88. //获取查找字符串在母串中的NSRange
  89. - (NSValue *)rangesOfString:(NSString *)searchString inString:(NSString *)str {
  90. NSRange searchRange = NSMakeRange(0, [str length]);
  91. NSRange range;
  92. if ((range = [str rangeOfString:searchString options:0 range:searchRange]).location != NSNotFound) {
  93. searchRange = NSMakeRange(NSMaxRange(range), [str length] - NSMaxRange(range));
  94. }
  95. return [NSValue valueWithRange:range];
  96. }
  97. - (NSUInteger)characterIndexAtPoint:(CGPoint)location {
  98. NSMutableAttributedString* attributedString = [self.attributedText mutableCopy];
  99. NSString *text = self.text;
  100. UIFont *font = self.font;
  101. if (!text || !font) return NSNotFound;
  102. CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString);
  103. CGSize constraintSize = CGSizeMake(self.bounds.size.width, CGFLOAT_MAX);
  104. CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), CGPathCreateWithRect(CGRectMake(0, 0, constraintSize.width, CGFLOAT_MAX), NULL), NULL);
  105. CFRelease(framesetter);
  106. NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
  107. NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:constraintSize];
  108. textContainer.lineFragmentPadding = 0.0;
  109. textContainer.lineBreakMode = self.lineBreakMode;
  110. textContainer.maximumNumberOfLines = self.numberOfLines;
  111. [layoutManager addTextContainer:textContainer];
  112. NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
  113. [textStorage addLayoutManager:layoutManager];
  114. CGFloat xOffset = location.x;
  115. CGFloat yOffset = location.y;
  116. NSRange glyphRange;
  117. CGFloat partialFraction;
  118. NSUInteger charIndex = [layoutManager characterIndexForPoint:CGPointMake(xOffset, yOffset) inTextContainer:textContainer fractionOfDistanceBetweenInsertionPoints:&partialFraction];
  119. CFRelease(frame);
  120. return partialFraction==1?NSNotFound:charIndex;
  121. }
  122. @end