[置顶] CoreText入门

学习了网上的一些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];



}[置顶] CoreText入门_第1张图片



完整的项目链接:http://pan.baidu.com/share/link?shareid=362100&uk=3674861929

转载请保留,原文链接:http://blog.csdn.net/zfpp25_/article/details/8639215

若发现有不合适或错误之处,还请批评指正,不胜感激。









你可能感兴趣的:([置顶] CoreText入门)