自制土方法实现CoreText超文本点击
来源:互联网 发布:淘宝买东西用什么支付 编辑:程序博客网 时间:2024/04/28 20:50
学习了一段时间CoreText 还是迷迷糊糊,下文是实现超链接自动识别,电话号码识别的一个土方法,大神直接飘过就好了。。。
#import <UIKit/UIKit.h>#import <CoreText/CoreText.h>typedef enum{ CLICK_TYPE_NONE = 0, CLICK_TYPE_LINK , CLICK_TYPE_PHONE,}CLICK_TYPE;@interface LinkView : UIView{ CTFrameRef _frame; NSInteger clickNum; BOOL isClick; CLICK_TYPE clickType;}@property (assign, nonatomic) CLICK_TYPE clickType;@property (assign, nonatomic) BOOL isClick;@property (assign, nonatomic) NSInteger clickNum;//点击的位置@property (retain, nonatomic) NSString *text;@property (retain, nonatomic) NSArray *linkArray;//存链接的Range数组@property (retain, nonatomic) NSArray *phoneArray;//存电话号码的Range数组@end
@synthesize text;@synthesize linkArray;@synthesize phoneArray;@synthesize isClick;@synthesize clickNum;@synthesize clickType;- (void)dealloc{ [text release]; [linkArray release]; [phoneArray release]; [super dealloc];}- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { // Initialization code self.backgroundColor = [UIColor clearColor]; } return self;}- (void)longPress:(UILongPressGestureRecognizer *)longPress{ if (longPress.state == UIGestureRecognizerStateBegan) { [self showMenu]; }}//是否包含汉字- (BOOL) containsChinese:(NSString *)str { for(int i = 0; i < [str length]; i++) { int a = [str characterAtIndex:i]; if( a > 0x4e00 && a < 0x9fff) return TRUE; } return FALSE;}//是否包含特殊符号,可以在这里判断超链接 结尾- (BOOL) containsSpecialSymbol:(NSString *)str{ NSSet *symbols = [NSSet setWithObjects:@" ",@",", nil]; for(int i = 0; i < [str length]; i++) { NSString *c = [str substringWithRange:NSMakeRange(i, 1)]; if ([symbols containsObject:c]) { return YES; } } return NO;}//电话号码是否合法- (BOOL)isValidatePhone:(NSString *)phone{ return NO;//本版本不进行电话号码得判断 NSString *phoneRegex = @"\\b(1)[358][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\\b"; NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@" , phoneRegex]; BOOL ret = [phoneTest evaluateWithObject:phone]; return ret;}- (BOOL)isMobileNumber:(NSString *)mobileNum{ /** * 手机号码 * 移动:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188 * 联通:130,131,132,152,155,156,185,186 * 电信:133,1349,153,180,189 */ NSString * MOBILE = @"^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$"; /** 10 * 中国移动:China Mobile 11 * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188 12 */ NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$"; /** 15 * 中国联通:China Unicom 16 * 130,131,132,152,155,156,185,186 17 */ NSString * CU = @"^1(3[0-2]|5[256]|8[56])\\d{8}$"; /** 20 * 中国电信:China Telecom 21 * 133,1349,153,180,189 22 */ NSString * CT = @"^1((33|53|8[09])[0-9]|349)\\d{7}$"; /** 25 * 大陆地区固话及小灵通 26 * 区号:010,020,021,022,023,024,025,027,028,029 27 * 号码:七位或八位 28 */ NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$"; NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE]; NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM]; NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU]; NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT]; NSPredicate *regextestphx = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", PHS]; if (([regextestmobile evaluateWithObject:mobileNum] == YES) || ([regextestcm evaluateWithObject:mobileNum] == YES) || ([regextestct evaluateWithObject:mobileNum] == YES) || ([regextestcu evaluateWithObject:mobileNum] == YES) || ([regextestphx evaluateWithObject:mobileNum])) { return YES; } else { return NO; }}//是否是连接开头- (BOOL)isValidateLink:(NSString *)Link{ if ([Link hasPrefix:@"http://"] || [Link hasPrefix:@"www."]) { return YES; } return NO;}//获取链接的NSRangeArray array 里面存的是链接的 NSRange- (NSArray *)getLinkRangeWithString:(NSString *)string{ NSMutableArray *rangeArray = [NSMutableArray arrayWithCapacity:0]; for (int loc = 0; loc < [string length]; ) { for (int len = 0; len <= [string length] - loc; ) { NSString *lenStr = [string substringWithRange:NSMakeRange(loc, len)]; if ([self isValidateLink:lenStr]) { if (![self containsSpecialSymbol:lenStr]) { //不包含特殊字符 以特殊字符或汉字结尾,或者结尾为空 if (loc + len == [string length]) { NSString *rangeStr = NSStringFromRange(NSMakeRange(loc, len)); [rangeArray addObject:rangeStr]; loc += len - 1; break; }else{ if ( [self containsSpecialSymbol:[string substringWithRange:NSMakeRange(loc + len, 1)]]) { NSString *rangeStr = NSStringFromRange(NSMakeRange(loc, len)); [rangeArray addObject:rangeStr]; loc += len - 1; break; } } } } len++; } loc++; } return rangeArray;}//获取电话的NSRange- (NSArray *)getPhoneRangeWithString:(NSString *)string{ NSMutableArray *rangeArray = [[NSMutableArray alloc]initWithCapacity:0]; for (int loc = 0; loc < [string length]; ) { for (int len = 0; len <= [string length] - loc; ) { NSString *lenStr = [string substringWithRange:NSMakeRange(loc, len)];// NSLog(@"lenStr: %@",lenStr); if ([self isMobileNumber:lenStr]) { NSString *rangeStr = NSStringFromRange(NSMakeRange(loc, len)); [rangeArray addObject:rangeStr]; loc += len - 1; break; } len++; } loc++; } return rangeArray;}//设置换行模式- (void)setAttString:(NSMutableAttributedString *)attString LineBreakMode:(CTLineBreakMode)mode{ CTParagraphStyleSetting lineBreakMode; CTLineBreakMode lineBreak = mode; lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode; lineBreakMode.value = &lineBreak; lineBreakMode.valueSize = sizeof(CTLineBreakMode); CTParagraphStyleSetting settings[] = { lineBreakMode }; CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 1); NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)style forKey:(id)kCTParagraphStyleAttributeName]; [attString addAttributes:attributes range:NSMakeRange(0, [attString length])];}- (void)drawRect:(CGRect)rect{ CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetTextMatrix(context, CGAffineTransformIdentity); CGContextSaveGState(context); //x,y轴方向移动 CGContextTranslateCTM(context, 0, self.bounds.size.height); //缩放x,y轴方向缩放,-1.0为反向1.0倍,坐标系转换,沿x轴翻转180度 CGContextScaleCTM(context, 1.0, -1.0); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, self.bounds); NSMutableAttributedString *attString = [[NSMutableAttributedString alloc]initWithString:self.text]; [attString beginEditing]; //设置字体属性 CTFontRef font = [self CTFontRefCTFontCreateFromUIFont:[UIFont systemFontOfSize:16.0f]]; [attString addAttribute:(id)kCTFontAttributeName value:(id)font range:NSMakeRange(0, [attString length])]; //让文字细一点//// CGFloat widthValue = -1.0; CFNumberRef strokeWidth = CFNumberCreate(NULL,kCFNumberFloatType,&widthValue); [attString addAttribute:(NSString*)(kCTStrokeWidthAttributeName) value:(id)strokeWidth range:NSMakeRange(0,[text length])]; [attString addAttribute:(NSString*)(kCTStrokeColorAttributeName) value:(id)[[UIColor whiteColor]CGColor] range:NSMakeRange(0,[text length])]; /////细一点 self.phoneArray = [self getPhoneRangeWithString:self.text]; self.linkArray = [self getLinkRangeWithString:self.text]; //设置字体颜色 [attString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor blackColor].CGColor range:NSMakeRange(0, [attString length])]; for (int i = 0; i < [self.linkArray count]; i ++) { [attString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor blueColor].CGColor range:NSRangeFromString([self.linkArray objectAtIndex:i])]; [attString addAttribute:(id)kCTUnderlineStyleAttributeName value:(id)[NSNumber numberWithInt: kCTUnderlineStyleSingle] range:NSRangeFromString([self.linkArray objectAtIndex:i])]; [attString addAttribute:(id)kCTUnderlineColorAttributeName value:(id)[UIColor greenColor] range:NSRangeFromString([self.linkArray objectAtIndex:i])]; } for (int i = 0; i < [self.phoneArray count]; i ++) { [attString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor redColor].CGColor range:NSRangeFromString([self.phoneArray objectAtIndex:i])]; } if (self.isClick) { switch (self.clickType) { case CLICK_TYPE_LINK: [attString removeAttribute:(id)kCTForegroundColorAttributeName range:NSRangeFromString([self.linkArray objectAtIndex:self.clickNum])]; [attString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UtilityHelper colorWithHexString:@"#002f6f"].CGColor range:NSRangeFromString([self.linkArray objectAtIndex:self.clickNum])]; break; case CLICK_TYPE_PHONE: [attString removeAttribute:(id)kCTForegroundColorAttributeName range:NSRangeFromString([self.phoneArray objectAtIndex:self.clickNum])]; [attString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[UIColor redColor].CGColor range:NSRangeFromString([self.phoneArray objectAtIndex:self.clickNum])]; break; default: break; } } //换行模式// [self setAttString:attString LineBreakMode:kCTLineBreakByWordWrapping]; [self setText:attString Alignment:kCTTextAlignmentLeft lineBreakMode:kCTLineBreakByCharWrapping]; [attString endEditing]; CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, [attString length]), path, NULL); _frame = frame; CTFrameDraw(frame, context); // CFRelease(frame); CFRelease(frameSetter); CFRelease(path);}//设置换行和对其方式-(void)setText:(NSMutableAttributedString *)attString Alignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode {[self setText:attString Alignment:alignment lineBreakMode:lineBreakMode range:NSMakeRange(0,[attString length])];}-(void)setText:(NSMutableAttributedString *)attString Alignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode range:(NSRange)range {// kCTParagraphStyleAttributeName > kCTParagraphStyleSpecifierAlignmentCTParagraphStyleSetting paraStyles[2] = {{.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void*)&alignment},{.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void*)&lineBreakMode},};CTParagraphStyleRef aStyle = CTParagraphStyleCreate(paraStyles, 2);[attString removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range]; // Work around for Apple leak[attString addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)aStyle range:range];CFRelease(aStyle);}//根据 点 判断 字符indexCFIndex CFIndexGet(CGPoint point,CTFrameRef frame){ //获取每一行 CFArrayRef lines = CTFrameGetLines(frame); CGPoint origins[CFArrayGetCount(lines)]; //获取每行的原点坐标 CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); CTLineRef line = NULL; CGPoint lineOrigin = CGPointZero; for (int i= 0; i < CFArrayGetCount(lines); i++) { CGPoint origin = origins[i]; CGPathRef path = CTFrameGetPath(frame); //获取整个CTFrame的大小 CGRect rect = CGPathGetBoundingBox(path); //坐标转换,把每行的原点坐标转换为uiview的坐标体系 CGFloat y = rect.origin.y + rect.size.height - origin.y; //判断点击的位置处于那一行范围内 if ((point.y <= y) && (point.x >= origin.x)) { line = CFArrayGetValueAtIndex(lines, i); lineOrigin = origin; break; } } point.x -= lineOrigin.x; //获取点击位置所处的字符位置,就是相当于点击了第几个字符 CFIndex index = CTLineGetStringIndexForPosition(line, point); return index;}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; //获取触摸点击当前view的坐标位置 CGPoint location = [touch locationInView:self]; CFIndex index = CFIndexGet(location, _frame); for (int i = 0; i< [self.linkArray count]; i++) { NSString *rangeStr = [self.linkArray objectAtIndex:i]; NSRange range = NSRangeFromString(rangeStr); if (index >= range.location && index <= range.location + range.length) { self.isClick = YES; self.clickNum = i; self.clickType = CLICK_TYPE_LINK; [self setNeedsDisplay]; } } for (int i = 0; i< [self.phoneArray count]; i++) { NSString *rangeStr = [self.phoneArray objectAtIndex:i]; NSRange range = NSRangeFromString(rangeStr); if (index >= range.location && index <= range.location + range.length) { self.isClick = YES; self.clickNum = i; self.clickType = CLICK_TYPE_PHONE; [self setNeedsDisplay]; } } }- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; //获取触摸点击当前view的坐标位置 CGPoint location = [touch locationInView:self]; CFIndex index = CFIndexGet(location, _frame); // NSLog(@"indexEnd:%ld",index); for (int i = 0; i< [self.linkArray count]; i++) { NSString *rangeStr = [self.linkArray objectAtIndex:i]; NSRange range = NSRangeFromString(rangeStr); if (index >= range.location && index <= range.location + range.length) { if (i == self.clickNum) { NSMutableString *linkText = [NSMutableString stringWithString:[self.text substringWithRange:range]]; if ([linkText hasPrefix:@"www:"]) { linkText = [NSMutableString stringWithFormat:@"http://%@",linkText]; } [UtilityHelper gatrackEvent:@"客户聊天详情页" label:@"跳转超链接"]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:linkText]]; } } } for (int i = 0; i< [self.phoneArray count]; i++) { NSString *rangeStr = [self.phoneArray objectAtIndex:i]; NSRange range = NSRangeFromString(rangeStr); if (index >= range.location && index <= range.location + range.length) { if (i == self.clickNum) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",[self.text substringWithRange:range]]]]; } } } self.isClick = NO; self.clickNum = -1; self.clickType = CLICK_TYPE_NONE; [self setNeedsDisplay];}- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{ self.isClick = NO; self.clickNum = -1; self.clickType = CLICK_TYPE_NONE; [self setNeedsDisplay];}//根据UIFont 获取 CTFontRef- (CTFontRef)CTFontRefCTFontCreateFromUIFont:(UIFont *)font{ CTFontRef ctFont =CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize, NULL); return ctFont;}@end
- 自制土方法实现CoreText超文本点击
- 用CoreText 实现显示可点击 的URL
- CoreText实现图文混排和点击事件
- CoreText实现图文混排和点击事件
- CoreText实现图文混排和点击事件
- CoreText实现图文混排和点击事件
- CoreText实现图文混排和点击事件
- CoreText实现图文混排和点击事件
- CoreText实现图文混排和点击事件
- ios CoreText实现图文混排和点击事件
- CoreText实现图文混排之点击事件
- CoreText:实现图文混排、点击图片功能(Swift)
- 盐碱地治理-泥炭土方法
- CoreText(六):用户点击
- 读 C 的方法和土方法
- 三角网法计算土方量
- 广西南宁治疗便秘的土方法
- IOS 开发—CoreText实现图文混排和点击事件
- 请不要忽略API的安全性
- win8使用技巧
- Oracle游标
- 安卓boot.img文件详细介绍-解包,编辑,打包
- T-SQL Tips: 用全局变量 @@version 查询服务器版本
- 自制土方法实现CoreText超文本点击
- Enumeration遍历Vector
- PHP的魔术世界
- 素数求和
- C++ Primer 第三章 标准库vector类型
- MySQL函数大全
- JavaScript多线程编程简介
- 关于系统架构的一些总结(1)
- windows下androidNDK环境配置