CoreText的简单实用demo

这里我封装了一个View用于显示文字与图片的混排,首先我们需要先在你的项目中添加coreText框架,在使用时直接导入头文件即可


核心代码:

.h中

#import <UIKit/UIKit.h>

#import <CoreText/CoreText.h>


使用代理,进行传值,这里我将段落的高度作为传递的参数,传给View的上级页面

@protocol ZHPCoreTextDelegate <NSObject>


@optional


- (void)ViewHeight:(CGFloat)height;


@end


@interface ZHPCoreTextView : UIView

- (id)initWithFrame:(CGRect)frame text:(NSString *)text imageNameArray:(NSArray *)imageNameArray delegate:(id<ZHPCoreTextDelegate>)delegate;

@property (nonatomic,copy)NSArray *imageArray;

@property (nonatomic,copy)NSString *text;

@property (nonatomic,assign)CGRect frame;

@property (nonatomic,strong)id<ZHPCoreTextDelegate> delegate;

@end


.m中

这里设置图片的高度与宽度

void RunDelegateDeallocCallback( void* refCon ){

    

}


CGFloat RunDelegateGetAscentCallback( void *refCon ){

    NSString *imageName = (__bridge NSString *)refCon;

    //    return [UIImage imageNamed:imageName].size.height;

    return 15;

}


CGFloat RunDelegateGetDescentCallback(void *refCon){

    return 0;

}


CGFloat RunDelegateGetWidthCallback(void *refCon){

    NSString *imageName = (__bridge NSString *)refCon;

    //    return [UIImage imageNamed:imageName].size.width;

    return 25;

}


- (id)initWithFrame:(CGRect)frame text:(NSString *)text imageNameArray:(NSArray *)imageNameArray delegate:(id<ZHPCoreTextDelegate>)delegate

{

    self = [super initWithFrame:frame];

    if (self) {

        self.backgroundColor = [UIColor whiteColor];

        _delegate = delegate;

        _text = text;

        _imageArray = imageNameArray;

    }

    return self;

}

drawRect,将图片与文字绘制在画布上

- (void)drawRect:(CGRect)rect

{

    [super drawRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetTextMatrix(context, CGAffineTransformIdentity);

    CGContextTranslateCTM(context, 0, self.bounds.size.height);

    CGContextScaleCTM(context, 1.0, -1.0);

    

    NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",_text] ];

    //为所有文本设置字体

    //[attributedString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:24] range:NSMakeRange(0, [attributedString length])]; // 6.0+

    

    

    [attString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)[UIColor orangeColor].CGColor range:NSMakeRange(0, _text.length)];

    for (int i = _imageArray.count-1; i>= 0; i--) {

        NSString *imageName = [_imageArray objectAtIndex:i];

        CTRunDelegateCallbacks imageCallbacks;

        imageCallbacks.version = kCTRunDelegateVersion1;

        imageCallbacks.dealloc = RunDelegateDeallocCallback;

        imageCallbacks.getAscent = RunDelegateGetAscentCallback;

        imageCallbacks.getDescent = RunDelegateGetDescentCallback;

        imageCallbacks.getWidth = RunDelegateGetWidthCallback;

        CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks, (__bridge void * _Nullable)(imageName));

        NSMutableAttributedString *imageAttributedString = [[NSMutableAttributedString alloc] initWithString:@" "];//空格用于给图片留位置

        [imageAttributedString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(__bridge id)runDelegate range:NSMakeRange(0, 1)];

        CFRelease(runDelegate);

        //    图片所占字节大小

        [imageAttributedString addAttribute:@"imageName" value:imageName range:NSMakeRange(0, 1)];

        //    图片插入的位置

        [attString insertAttributedString:imageAttributedString atIndex:_text.length];

        

    }

    

    

    UIFont *font = [UIFont systemFontOfSize:13];

    CTFontRef fontRef = CTFontCreateWithName((__bridge CFStringRef)font.fontName,

                                             font.pointSize,

                                             NULL);

    [attString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)fontRef range:NSMakeRange(0, [attString length])];

    

    

    CFRelease(fontRef);

    //换行模式

    CTParagraphStyleSetting lineBreakMode;

    CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;

    lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;

    lineBreakMode.value = &lineBreak;

    lineBreakMode.valueSize = sizeof(CTLineBreakMode);

    //行距

    CGFloat _linespace = 2.0f;

    CTParagraphStyleSetting lineSpaceSetting;

    lineSpaceSetting.spec = kCTParagraphStyleSpecifierLineSpacing;

    lineSpaceSetting.value = &_linespace;

    lineSpaceSetting.valueSize = sizeof(float);

    //首行缩进

    CGFloat fristlineindent = 24.0f;

    CTParagraphStyleSetting fristline;

    fristline.spec = kCTParagraphStyleSpecifierFirstLineHeadIndent;

    fristline.value = &fristlineindent;

    fristline.valueSize = sizeof(float);

    CTParagraphStyleSetting settings[] = {

        lineBreakMode,

        lineSpaceSetting,

        fristline

    };

    

    CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 3);

    

    

    // build attributes

    NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)style forKey:(id)kCTParagraphStyleAttributeName ];

    

    // set attributes to attributed string

    [attString addAttributes:attributes range:NSMakeRange(0, [attString length])];

    

    

    

    CGMutablePathRef path = CGPathCreateMutable();

    CGRect bounds = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height);

    CGPathAddRect(path, NULL, bounds);

    

    CTFramesetterRef framesetter =

    CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); //3

    

    CTFrameRef frame =

    CTFramesetterCreateFrame(framesetter,

                             CFRangeMake(0, 0), path, NULL);

    

    CTFrameDraw(frame, context); //4

    //    计算段落高度

    NSArray *linesArray = (NSArray *) CTFrameGetLines(frame);

    

    CGPoint origins[[linesArray count]];

    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);

    

    int line_y = (int) origins[[linesArray count] -1].y//最后一行line的原点y坐标

    

    CGFloat ascent;

    CGFloat descent;

    CGFloat leading;

    

    CTLineRef line = (__bridge CTLineRef) [linesArray objectAtIndex:[linesArray count]-1];

    CTLineGetTypographicBounds(line, &ascent, &descent, &leading);

    [_delegate ViewHeight:self.bounds.size.height - line_y + (int) descent +1];

    //+1为了纠正descent转换成int小数点后舍去的值

    

    

    

    CFArrayRef lines = CTFrameGetLines(frame);

    CGPoint lineOrigins[CFArrayGetCount(lines)];

    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), lineOrigins);

    

    for (int i = 0; i < CFArrayGetCount(lines); i++) {

        CTLineRef line = CFArrayGetValueAtIndex(lines, i);

        CGFloat lineAscent;

        CGFloat lineDescent;

        CGFloat lineLeading;

        CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, &lineLeading);

        

        CFArrayRef runs = CTLineGetGlyphRuns(line);

        for (int j = 0; j < CFArrayGetCount(runs); j++) {

            CGFloat runAscent;

            CGFloat runDescent;

            CGPoint lineOrigin = lineOrigins[i];

            CTRunRef run = CFArrayGetValueAtIndex(runs, j);

            NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);

            CGRect runRect;

            runRect.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0,0), &runAscent, &runDescent, NULL);

            

            runRect=CGRectMake(lineOrigin.x + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL), lineOrigin.y - runDescent, runRect.size.width, runAscent + runDescent);

            

            NSString *imageName = [attributes objectForKey:@"imageName"];

            //图片渲染逻辑

            if (imageName) {

                UIImage *image = [UIImage imageNamed:imageName];

                if (image) {

                    CGRect imageDrawRect;

                    imageDrawRect.size = CGSizeMake(20, 20);

                    imageDrawRect.origin.x = runRect.origin.x + lineOrigin.x ;

                    imageDrawRect.origin.y = lineOrigin.y-5;

                    CGContextDrawImage(context, imageDrawRect, image.CGImage);

                }

            }

        }

    }

    

    CFRelease(frame); //5

    CFRelease(path);

    CFRelease(framesetter);

    

}

其他文件使用时:

- (void)viewDidLoad {

    [super viewDidLoad];

   

    

    _view = [[ZHPCoreTextView alloc] initWithFrame:CGRectMake(100, 100, self.view.frame.size.width/2, self.view.frame.size.height/2) text:@"什么时候变得不安,和没有归属感。然后还一味任性地埋怨,这不是我的错,如此焦躁,和孩子气的自己。忍不住的想放逐和流浪。看着依旧苍白的自己,像蒲草一样飘来飘去" imageNameArray:@[@".png",@".png",@".png"] delegate:self];

    _view.backgroundColor = [UIColor whiteColor];

    _view.center = self.view.center;

    [self.view addSubview:_view];

    


    

}

//通过代理方法获得段落的高度

- (void)ViewHeight:(CGFloat)height{


    NSLog(@"段落高度为:%f",height);

    

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值