学习了网上的一些CoreText知识之后,总结了一下学习成果,自定义了一个Label控件。
Label特点:
1、可以设置文本中某些字段为关键字;
2、可以设置文本颜色和其中关键字的颜色;
3、可以设置文本下划线样式和其中关键字下划线样式;
4、可以指定文本字体与大小和其中关键字的字体与大小;
5、可以响应关键字点击;
说明一下其中的关键类的意义:
CHLabel.h 自定义的控件,继承自UILabel;
TestViewController.h 是项目的根视图控制器,其中使用了CHLabel;
下面看代码:
CHLabel 代码实现:
#import <UIKit/UIKit.h> #import<CoreText/CoreText.h> typedef enum { kCHLabelUnderlineStyleNone = 0 , kCHLabelUnderlineStyleSingle , kCHLabelUnderlineStyleThick , kCHLabelUnderlineStyleDouble } CHLabelUnderlineStyle; @protocol CHLabelDelegate; @interface CHLabel : UILabel { NSString *_textCH; //文本 UIColor *_textColorCH; //文本颜色 UIFont *_textFontCH; //文本字体 CHLabelUnderlineStyle _textUnderlineStyle; //文本下划线 NSString *_textKeyWordCH; //关键字 UIColor *_textKeyWordColorCH; //关键字颜色 UIFont *_keyWordFontCH; //关键字字体 CHLabelUnderlineStyle _keyWordUnderlineStyle;//关键字下划线 NSMutableArray *_keyWordsCH; //关键字数组 NSMutableAttributedString *_attributedString; //属性字符串 } @property (nonatomic, copy) NSString *textCH; @property (nonatomic, retain) UIColor *textColorCH; @property (nonatomic, copy) NSString *textKeyWordCH; @property (nonatomic, retain) UIColor *textKeyWordColorCH; @property (nonatomic, retain) UIFont *textFontCH; @property (nonatomic, retain) UIFont *keyWordFontCH; @property (nonatomic, retain) NSMutableArray *keyWordsCH; @property (nonatomic, retain) NSMutableAttributedString *attributedString; @property (nonatomic, retain) id<CHLabelDelegate> delegate; - (void) setText:(NSString *) textString andKeyWord:(NSString *) keyWord; - (void) setTextColor:(UIColor *)textColor andKeyWordColor:(UIColor *) keyWordColor; - (void) setTextFont: (UIFont *)textFont andKeyWordFont:(UIFont *) keyWordFont; - (void) setTextUnderlineStyle: (CHLabelUnderlineStyle)textUnderlineStyle andKeyWordUnderlineStyle:(CHLabelUnderlineStyle) keyWordUnderlineStyle; @end @protocol CHLabelDelegate <NSObject> @optional - (void) CHLabel:(CHLabel *) chLabel tapOnKeyWord:(NSString *) keyWord; @end #import "CHLabel.h" @implementation CHLabel @synthesize textCH = _textCH; @synthesize textColorCH = _textColorCH; @synthesize textKeyWordCH = _textKeyWordCH; @synthesize textKeyWordColorCH = _textKeyWordColorCH; @synthesize textFontCH = _textFontCH; @synthesize keyWordFontCH = _keyWordFontCH; @synthesize keyWordsCH = _keyWordsCH; @synthesize attributedString = _attributedString; @synthesize delegate; void safeRelease(id pointer) { if (!pointer) { [pointer release]; pointer = nil; } } - (void) dealloc { safeRelease(_textCH); safeRelease(_textColorCH); safeRelease(_textKeyWordCH); safeRelease(_textKeyWordColorCH); safeRelease(_textFontCH); safeRelease(_keyWordFontCH); safeRelease(_keyWordsCH); safeRelease(_attributedString); safeRelease(delegate); [super dealloc]; } - (void) initializtion { _textKeyWordCH = nil; _textKeyWordColorCH = nil; _keyWordsCH = [[NSMutableArray alloc] init]; } - (id) init { if (self = [super init]) { [self initializtion]; } return self; } - (id)initWithFrame:(CGRect)frame { if ([super initWithFrame:frame]) { [self initializtion]; } return self; } - (void) setText:(NSString *) textString andKeyWord:(NSString *) keyWord { if (self.text != textString) { self.text = textString; self.textCH = textString; } [self fetchKeywordRange:keyWord]; } - (void) setTextColor:(UIColor *)textColor andKeyWordColor:(UIColor *) keyWordColor { self.textColorCH = textColor; self.textKeyWordColorCH = keyWordColor; } - (void) setTextFont:(UIFont *)textFont andKeyWordFont:(UIFont *) keyWordFont { self.textFontCH = textFont; self.keyWordFontCH = keyWordFont; } - (void) setTextUnderlineStyle: (CHLabelUnderlineStyle)textUnderlineStyle andKeyWordUnderlineStyle:(CHLabelUnderlineStyle) keyWordUnderlineStyle { _textUnderlineStyle = textUnderlineStyle; _keyWordUnderlineStyle = keyWordUnderlineStyle; } - (void) fetchKeywordRange:(NSString *)keyWord { if (nil == keyWord) { return; } NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:self.text]; NSUInteger count = 0, length = [mutableAttributedString length]; NSRange range = NSMakeRange(0, length); count = 0, length = [mutableAttributedString length]; range = NSMakeRange(0, length); while(range.location != NSNotFound) { range = [[mutableAttributedString string] rangeOfString:keyWord options:0 range:range]; if(range.location != NSNotFound) { NSValue *value = [NSValue valueWithRange:range]; if (range.length > 0) { [self.keyWordsCH addObject:value]; } range = NSMakeRange(range.location + range.length, length - (range.location + range.length)); count++; } } } - (int) labelUnderlineType:(CHLabelUnderlineStyle) lType { int underLineType; switch (lType) { case 0: underLineType = kCTUnderlineStyleNone; break; case 1: underLineType = kCTUnderlineStyleSingle; break; case 2: underLineType = kCTUnderlineStyleThick; break; case 3: underLineType = kCTUnderlineStyleDouble; break; default: underLineType = kCTUnderlineStyleNone; break; } return underLineType; } - (NSAttributedString *) richString:(NSString *) textString { int length = [textString length]; if (self.attributedString) { self.attributedString = nil; } self.attributedString = [[NSMutableAttributedString alloc] initWithString:textString]; [self.attributedString addAttribute:(NSString *)(kCTForegroundColorAttributeName) value:(id)self.textColorCH.CGColor range:NSMakeRange(0, length)]; int numType = 0; CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberIntType, &numType); [self.attributedString addAttribute:(NSString *)kCTLigatureAttributeName value:(id)cfNum range:NSMakeRange(0, length)]; float fNum =3.0; CFNumberRef cfNum2 = CFNumberCreate(NULL, kCFNumberFloatType, &fNum); [self.attributedString addAttribute:(NSString *)(kCTStrokeColorAttributeName) value:(id)cfNum2 range:NSMakeRange(0, length)]; if (!self.textFontCH) { self.textFontCH = self.font; } CTFontRef ctFont = CTFontCreateWithName((CFStringRef)self.textFontCH.fontName, self.textFontCH.pointSize, NULL); [self.attributedString addAttribute:(NSString *)(kCTFontAttributeName) value:(id)ctFont range:NSMakeRange(0, length)]; int underLineType = [self labelUnderlineType:_textUnderlineStyle]; CFNumberRef cfUnderLine = CFNumberCreate(NULL, kCTUnderlineStyleThick, &underLineType); [self.attributedString addAttribute:(NSString *)(kCTUnderlineStyleAttributeName) value:(id)cfUnderLine range:NSMakeRange(0, length)]; if (self.textKeyWordColorCH != nil) { for (NSValue *value in self.keyWordsCH) { NSRange keyRange = [value rangeValue]; [self.attributedString addAttribute:(NSString *)(kCTForegroundColorAttributeName) value:(id)self.textKeyWordColorCH.CGColor range:keyRange]; if (!self.keyWordFontCH) { self.keyWordFontCH = self.font; } CTFontRef ctFont = CTFontCreateWithName((CFStringRef)self.keyWordFontCH.fontName, self.keyWordFontCH.pointSize, NULL); [self.attributedString addAttribute:(NSString *)(kCTFontAttributeName) value:(id)ctFont range:keyRange]; int underLineType = [self labelUnderlineType:_keyWordUnderlineStyle]; CFNumberRef cfUnderLine = CFNumberCreate(NULL, kCTUnderlineStyleThick, &underLineType); [self.attributedString addAttribute:(NSString *)(kCTUnderlineStyleAttributeName) value:(id)cfUnderLine range:keyRange]; [self.attributedString addAttribute:@"option" value:[[self.attributedString string] substringWithRange:keyRange] range:keyRange];//弹出alert时候需要 } } return [[self.attributedString copy] autorelease]; } - (void) drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGContextConcatCTM(context, CGAffineTransformScale(CGAffineTransformMakeTranslation(0, rect.size.height+6.5), 1.f, -1.f)); CGContextSetTextPosition(context, 0.0, 0.0); CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef) [self richString:self.text]); // NSLog(@"AttributedString:%@", [self richString:self.text font:self.font]); CGMutablePathRef leftColumnPath = CGPathCreateMutable(); CGPathAddRect(leftColumnPath, NULL, rect); CTFrameRef leftFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), leftColumnPath, NULL); CTFrameDraw(leftFrame, context); CGContextRestoreGState(context); CGPathRelease(leftColumnPath); CFRelease(framesetter); } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; CGPoint tapLocation = [[touches anyObject] locationInView:self]; int total_height = [self getAttributedStringHeightWithString:self.attributedString WidthValue:self.frame.size.width];//width为自身宽度 //判断点击是否超出范围 if (tapLocation.y >= total_height) { return; } /** 1. Setup CTFramesetter **/ CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.attributedString); /** 2. Create CTFrame **/ CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, 1000));//height越大越好, CTFrameRef textFrameForKey = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); //[self drawFrame:textFrameForKey inContext:nil forString:nil]; CFRelease (path); CFRelease (framesetter); //CTFrameGetLineOrigins NSArray *linesArray = (NSArray *) CTFrameGetLines(textFrameForKey); CGPoint origins[[linesArray count]]; CTFrameGetLineOrigins(textFrameForKey, CFRangeMake(0, 0), origins); CFArrayRef lines = CTFrameGetLines(textFrameForKey); CGFloat ascent; CGFloat descent; CGFloat leading; CTLineRef line = (CTLineRef) [linesArray objectAtIndex:0]; CTLineGetTypographicBounds(line, &ascent, &descent, &leading); //CFIndex linesCount = CFArrayGetCount(lines); int line_y = 1000- (int)origins[0].y; //第一行line的原点y坐标 int line_height = line_y + (int)descent +1; //每行的高度 int current_line = tapLocation.y/line_height; CFIndex curentIndex = CTLineGetStringIndexForPosition((CTLineRef)CFArrayGetValueAtIndex(lines, current_line),tapLocation); //判断超出范围 if (curentIndex >[self.attributedString length]) { return; } NSRange currentRange = NSMakeRange(0, [self.attributedString length]); //curentIndex NSDictionary *dic = [self.attributedString attributesAtIndex:curentIndex-1 effectiveRange:¤tRange]; id option = [dic valueForKey:@"option"]; if (option) { if ([delegate respondsToSelector:@selector(CHLabel:tapOnKeyWord:)]) { [delegate CHLabel:self tapOnKeyWord:(NSString *)[dic valueForKey:@"option"]]; } } } //获取coretext高度 - (int)getAttributedStringHeightWithString:(NSAttributedString *)string WidthValue:(int) width { int total_height = 0; //string 为要计算高度的NSAttributedString CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string); CGRect drawingRect = CGRectMake(0, 0, width, 1000); //这里的高要设置足够大 CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, drawingRect); CTFrameRef textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL); CGPathRelease(path); CFRelease(framesetter); NSArray *linesArray = (NSArray *) CTFrameGetLines(textFrame); CGPoint origins[[linesArray count]]; CTFrameGetLineOrigins(textFrame, CFRangeMake(0, 0), origins); int line_y = (int) origins[[linesArray count] -1].y; //最后一行line的原点y坐标 CGFloat ascent; CGFloat descent; CGFloat leading; CTLineRef line = (CTLineRef) [linesArray objectAtIndex:[linesArray count]-1]; CTLineGetTypographicBounds(line, &ascent, &descent, &leading); total_height = 1000 - line_y + (int) descent +1; //+1为了纠正descent转换成int小数点后舍去的值 CFRelease(textFrame); return total_height; } @end TestViewController.h 代码实现: @interface TestViewController : UIViewController <CHLabelDelegate> { IBOutlet UITextField *textString; IBOutlet UITextField *keyString; } - (IBAction) showText:(id)sender; @end #import "TestViewController.h" @interface TestViewController () @end @implementation TestViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (IBAction) showText:(id)sender { [textString resignFirstResponder]; [keyString resignFirstResponder]; CHLabel *label = [[CHLabel alloc] initWithFrame:CGRectMake(10, 260, 300, 200)]; [label setUserInteractionEnabled:YES]; [label setText:textString.text andKeyWord:keyString.text]; [label setTextColor:[UIColor redColor] andKeyWordColor:[UIColor blueColor]]; [label setTextUnderlineStyle:kCHLabelUnderlineStyleSingle andKeyWordUnderlineStyle:kCHLabelUnderlineStyleDouble]; [label setTextFont:[UIFont systemFontOfSize:20] andKeyWordFont:[UIFont boldSystemFontOfSize:30]]; label.backgroundColor = [UIColor lightGrayColor]; [label setNumberOfLines:0]; label.delegate = self; NSArray *fontArray = [UIFont familyNames]; NSString *fontName; if ([fontArray count]) { fontName = [fontArray objectAtIndex:0]; } [label setFont:[UIFont fontWithName:fontName size:20]]; [self.view addSubview:label]; // [label setNeedsDisplay]; [label release]; } - (void)viewDidLoad { [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark CHLabelDelegate - (void) CHLabel:(CHLabel *) chLabel tapOnKeyWord:(NSString *) keyWord { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"notice" message:[NSString stringWithFormat:@"Tap on keyWord:%@", keyWord] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; [alert release];
完整的项目链接:http://pan.baidu.com/share/link?shareid=362100&uk=3674861929
转载请保留,原文链接:http://blog.csdn.net/zfpp25_/article/details/8639215
若发现有不合适或错误之处,还请批评指正,不胜感激。