Coretext 圖文混排 一個(gè) view的實(shí)現(xiàn)

一個(gè)老司機(jī)的 Coretext圖文混排 非常容易理解

簡(jiǎn)書(shū):老司機(jī)Wicky ?可以點(diǎn)擊查看.

//注:對(duì)上面那位老司機(jī)的 demo 代碼一行一行的注釋 供自己以后學(xué)習(xí)參考.感謝 ?老司機(jī)Wicky


#import "tuwenview.h"

#import@implementation tuwenview

// Only override drawRect: if you perform custom drawing.

// An empty implementation adversely affects performance during animation.

- (void)drawRect:(CGRect)rect {

// Drawing code

[super drawRect:rect];

//獲取到上下文

CGContextRef context = UIGraphicsGetCurrentContext();

//實(shí)現(xiàn)翻轉(zhuǎn)

CGContextSetTextMatrix(context, CGAffineTransformIdentity);

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

CGContextScaleCTM(context, 1.0, -1.0);

//屬性字符串

NSMutableAttributedString *attributestr = [[NSMutableAttributedString alloc]initWithString:@"\\n這里在測(cè)試圖文混排,\\n我是一個(gè)富文本"];

//為圖片設(shè)置CTRunDelegate,delegate決定留給圖片的空間大小

CTRunDelegateCallbacks callbacks;

memset(&callbacks, 0, sizeof(CTRunDelegateCallbacks));

callbacks.version = kCTRunDelegateVersion1;

callbacks.getAscent = ascentCallBacks;

callbacks.getDescent = descentCallBacks;

callbacks.getWidth = ?widthCallBacks;

NSDictionary *dicpic = @{@"height":@129,@"width":@400};

//通過(guò)以上創(chuàng)建了圖片顯示大小的代理

CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (__bridge void * )(dicpic));

//不能直接顯示圖片而是要在原來(lái)的屬性字符創(chuàng)中插入一個(gè)占位符

unichar placeholderchar = 0xfffc;

NSString *placeholderStr = [NSString stringWithCharacters:&placeholderchar length:1];

//將占位字符串轉(zhuǎn)化為屬性字符串

NSMutableAttributedString * placeHolderAttrStr = [[NSMutableAttributedString alloc] initWithString:placeholderStr];

//不太明白這里是什么意思??????

CFAttributedStringSetAttribute((CFMutableAttributedStringRef)placeHolderAttrStr, CFRangeMake(0, 1), kCTRunDelegateAttributeName, delegate);

//這個(gè) delegate 使用完畢 釋放內(nèi)存 已經(jīng)存儲(chǔ)在placeHolderAttrStr中了

CFRelease(delegate);

//將這個(gè)屬性字符串插入到需要混排的屬性字符串中間

[attributestr insertAttributedString:placeHolderAttrStr atIndex:8];

//下面是獲取到 ctframe 的套路

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributestr);

//定義一個(gè)需要將混排后的顯示區(qū)域

CGMutablePathRef path = CGPathCreateMutable();

//設(shè)置混排的區(qū)域?yàn)閺膹漠?dāng)前視圖的左上角開(kāi)始的矩形區(qū)域

CGPathAddRect(path, NULL, self.bounds);

//需要排列的屬性文本的大小長(zhǎng)度 ?不同長(zhǎng)度 排出來(lái)的 frame 大小不一樣

NSInteger length = attributestr.length;

//通過(guò)前面的長(zhǎng)度回去 frame ?(其中最后一個(gè)參數(shù)的用來(lái)定制這個(gè) ctframe)

CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, length), path, NULL);

//混排

CTFrameDraw(frame, context);

//拿到需要排列的圖片

UIImage *image = [UIImage imageNamed:@"bg.png"];

//從上面混排的frame 計(jì)算實(shí)際 image 的 frame ?這個(gè)計(jì)算大小的方式自定義

CGRect imgframerect = [self calculateImageRectWithFrame:frame];

CGContextDrawImage(context, imgframerect, image.CGImage);

//手動(dòng)釋放內(nèi)存

CFRelease(frame);

CFRelease(path);

CFRelease(framesetter);

//關(guān)閉上下文 忘了怎么寫(xiě)

}

//為了代理獲取到這個(gè)圖片占位符的實(shí)際大小使用的幾個(gè) C 函數(shù)

static CGFloat ascentCallBacks (void * ref){

return [(NSNumber *)[(__bridge NSDictionary *)ref valueForKey:@"height"] floatValue];

}

//獲取到 descent

static CGFloat descentCallBacks(void * ref)

{

return 0;

}

//獲取到 width

static CGFloat widthCallBacks(void * ref)

{

return [(NSNumber *)[(__bridge NSDictionary *)ref valueForKey:@"width"] floatValue];

}

//如何通過(guò)全部的計(jì)算得到圖片的 frame 的方法 ?定制化

- (CGRect)calculateImageRectWithFrame:(CTFrameRef) rect{

//獲取到繪制區(qū)域的所有 ctlines

NSArray *arraylines = (NSArray *)CTFrameGetLines(rect);

//獲取到 lines 的數(shù)量

NSInteger count = [arraylines count];

CGPoint points[count];

//構(gòu)建一個(gè)數(shù)組每一個(gè) ctrun的起始點(diǎn) 將誒一個(gè) ctlines 的初始點(diǎn)保存在 points 中間

CTFrameGetLineOrigins(rect, CFRangeMake(0, 0), points);

for(int i = 0 ; i < count ;i++){

//循環(huán)拿到每一行 lines

CTLineRef line = (__bridge CTLineRef)arraylines[i];

//獲取到每一個(gè)行中的所有的 ctrun

NSArray *ctruns = (NSArray *)CTLineGetGlyphRuns(line);

//使用 for 循環(huán)遍歷該行的所有的 ctrun

for(int j = 0; j < ctruns.count; j++){

CTRunRef run = (__bridge CTRunRef)ctruns[j];

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

//獲取到該 run 的代理

CTRunDelegateRef delegate = (__bridge CTRunDelegateRef)[attributes valueForKey:(id)kCTRunDelegateAttributeName];

//如果代理為空 進(jìn)入到下一個(gè)循環(huán)

if(delegate == nil){

continue;

}

NSDictionary *dic = CTRunDelegateGetRefCon(delegate);

//如果有代理 但是代理屬性不是 前面賦值的字典類型的 繼續(xù)下一個(gè)循環(huán)

if(![dic isKindOfClass:[NSDictionary class]]){

continue;

}

//到這里說(shuō)明是找到自己的代理了 類型為 字典類型的

//將這個(gè)ctrun 的起點(diǎn)保存起來(lái)

CGPoint point = points[i];

//上

CGFloat ascent;

//下

CGFloat ?descent;

CGRect boundsRun;

//獲取到寬 (這個(gè)寬度為緊貼的寬度)

boundsRun.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, NULL);

//已經(jīng)有值了 可以計(jì)算出高度

boundsRun.size.height = ascent + descent;

//從當(dāng)前的行中獲取到該 run 的偏移量 ?這個(gè)類似于固定值 應(yīng)該可以改變

CGFloat xoffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL);

//設(shè)置 origh 的x y

boundsRun.origin.x = point.x + xoffset;

boundsRun.origin.y = point.y - descent;

//繪到屏幕 拿到當(dāng)前的 ctframe的 path

CGPathRef path = CTFrameGetPath(rect);

CGRect colRect = CGPathGetBoundingBox(path);

//校正 rect

CGRect imageBounds = CGRectOffset(boundsRun, colRect.origin.x, colRect.origin.y);

//返回img的 rect

return imageBounds;

}

}

return CGRectZero;;

}

@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 最近在網(wǎng)上看了一些大牛的文章,自己也試著寫(xiě)了一下,感覺(jué)圖文混排真的很強(qiáng)大。 廢話不多說(shuō),開(kāi)始整 先上效果圖跟代碼,...
    AllureJM閱讀 1,024評(píng)論 0 1
  • CoreText是iOS/OSX中文本顯示的一個(gè)底層框架,它是用C語(yǔ)言寫(xiě)成的,有快速簡(jiǎn)單的優(yōu)勢(shì)。iOS中的Text...
    小貓仔閱讀 5,030評(píng)論 2 9
  • 本章前言 在上一篇《基于 CoreText 的排版引擎:基礎(chǔ)》中,我們學(xué)會(huì)了排版的基礎(chǔ)知識(shí),現(xiàn)在我們來(lái)增加復(fù)雜性,...
    赤色追風(fēng)閱讀 889評(píng)論 0 2
  • iOS沒(méi)有現(xiàn)成的支持圖文混排的控件,而要用多個(gè)基礎(chǔ)控件組合拼成圖文混排這樣復(fù)雜的排版,是件很苦逼的事情。對(duì)此的解決...
    清風(fēng)沐沐閱讀 686評(píng)論 0 2
  • blog.csdn.net CoreText實(shí)現(xiàn)圖文混排 - 博客頻道 CoreText實(shí)現(xiàn)圖文混排 也好久沒(méi)來(lái)寫(xiě)...
    K_Gopher閱讀 619評(píng)論 0 0