iOS 基础排版引擎 - CoreText
2019-06-11 本文已影响0人
iOS小童
CoreText
-
创建AttributedString,定义样式
-
通过 CFAttributedStringRef 生成 CTFramesetter
-
通过CTFramesetter得到CTFrame
-
绘制 (CTFrameDraw)
-
如果有图片存在,先在AttributedString 对应位置添加占位符
-
通过回调函数确定图片的宽高(CTRunDelegateCallbacks)
-
遍历到对应CTRun上、获取对应CGRect、绘制图片(CGContextDrawImage)
单行文本 - layingOut
- (void)drawRect:(CGRect)rect {
// Drawing code
// Initialize a graphics context in iOS.
CGContextRef context = UIGraphicsGetCurrentContext();
// Flip the context coordinates, in iOS only.
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Set the text matrix.
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
// Create a path which bounds the area where you will be drawing text.
// The path need not be rectangular.
CGMutablePathRef path = CGPathCreateMutable();
// In this simple example, initialize a rectangular path.
CGRect bounds = CGRectMake(10.0,rect.size.height - 300.0, 200.0, 200.0);
CGPathAddRect(path, NULL, bounds );
// Initialize a string.
CFStringRef textString = CFSTR("Hello, World! I know nothing in the world that has as much power as a word. Sometimes I write one, and I look at it, until it begins to shine.");
// Create a mutable attributed string with a max length of 0.
// The max length is a hint as to how much internal storage to reserve.
// 0 means no hint.
CFMutableAttributedStringRef attrString =
CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
// Copy the textString into the newly created attrString
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0),
textString);
// Create a color that will be added as an attribute to the attrString.
// 字体颜色设置.
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12), kCTForegroundColorAttributeName, [UIColor redColor].CGColor);
// 大小设置
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12), kCTFontAttributeName, (__bridge CFTypeRef)([UIFont boldSystemFontOfSize:18]));
// 下划线设置
/***
kCTUnderlineStyleNone = 0x00,
kCTUnderlineStyleSingle = 0x01,
kCTUnderlineStyleThick = 0x02,
kCTUnderlineStyleDouble = 0x09
****/
CFAttributedStringSetAttribute(attrString, CFRangeMake(12, 24), kCTUnderlineColorAttributeName, [UIColor greenColor].CGColor);
CFAttributedStringSetAttribute(attrString, CFRangeMake(12, 24), kCTUnderlineStyleAttributeName, (__bridge CFTypeRef)[NSNumber numberWithInt:kCTUnderlineStyleSingle]);
// 字与字水平垂直间距调整
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12), kCTKernAttributeName, (__bridge CFTypeRef)[NSNumber numberWithInt:5]);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12), kCTSuperscriptAttributeName, (__bridge CFTypeRef)[NSNumber numberWithInt:5]);
// 背景颜色设置
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12), kCTBackgroundColorAttributeName, [UIColor grayColor].CGColor);
// Create the framesetter with the attributed string.
CTFramesetterRef framesetter =
CTFramesetterCreateWithAttributedString(attrString);
CFRelease(attrString);
// Create a frame.
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, 0), path, NULL);
// Draw the specified frame in the given context.
CTFrameDraw(frame, context);
// Release the objects we used.
CFRelease(frame);
CFRelease(path);
CFRelease(framesetter);
}
竖版文本绘制 - ColumnsText
- (void)drawRect:(CGRect)rect {
// Drawing code
// Initialize a graphics context in iOS.
CGContextRef context = UIGraphicsGetCurrentContext();
// Flip the context coordinates in iOS only.
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Set the text matrix.
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:@"Hello, World! I know nothing in the world that has as much power as a word. Sometimes I write one, and I look at it, until it begins to shine."];
// Create the framesetter with the attributed string.
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);
// Call createColumnsWithColumnCount function to create an array of
// three paths (columns).
CFArrayRef columnPaths = [self createColumnsWithColumnCount:3];
CFIndex pathCount = CFArrayGetCount(columnPaths);
CFIndex startIndex = 0;
int column;
// Create a frame for each column (path).
for (column = 0; column < pathCount; column++) {
// Get the path for this column.
CGPathRef path = (CGPathRef)CFArrayGetValueAtIndex(columnPaths, column);
// Create a frame for this column and draw it.
CTFrameRef frame = CTFramesetterCreateFrame(
framesetter, CFRangeMake(startIndex, 0), path, NULL);
CTFrameDraw(frame, context);
// Start the next frame at the first character not visible in this frame.
CFRange frameRange = CTFrameGetVisibleStringRange(frame);
startIndex += frameRange.length;
CFRelease(frame);
}
CFRelease(columnPaths);
CFRelease(framesetter);
}
- (CFArrayRef)createColumnsWithColumnCount:(int)columnCount
{
int column;
CGRect* columnRects = (CGRect*)calloc(columnCount, sizeof(*columnRects));
// Set the first column to cover the entire view.
columnRects[0] = self.bounds;
// Divide the columns equally across the frame's width.
CGFloat columnWidth = CGRectGetWidth(self.bounds) / columnCount;
for (column = 0; column < columnCount - 1; column++) {
CGRectDivide(columnRects[column], &columnRects[column],
&columnRects[column + 1], columnWidth, CGRectMinXEdge);
}
// Inset all columns by a few pixels of margin.
for (column = 0; column < columnCount; column++) {
columnRects[column] = CGRectInset(columnRects[column], 8.0, 15.0);
}
// Create an array of layout paths, one for each column.
CFMutableArrayRef array =
CFArrayCreateMutable(kCFAllocatorDefault,
columnCount, &kCFTypeArrayCallBacks);
for (column = 0; column < columnCount; column++) {
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, columnRects[column]);
CFArrayInsertValueAtIndex(array, column, path);
CFRelease(path);
}
free(columnRects);
return array;
}