- (void)drawRect:(CGRect)rect{
[super drawRect:rect];
//获取上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//坐标系x转换 UIKit -> CoreText
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
//绘制路径
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, self.bounds);
//显示的字符串
NSAttributedString *attString = [[NSAttributedString alloc]initWithString:@"this is a text"];
//创建CTFrameRef实例
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attString.length), path, NULL);
//将CTFrame对象画到上下文中
CTFrameDraw(frame, context);
//释放对象
CFRelease(frame);
CFRelease(path);
CFRelease(frameSetter);
}
swift
class CoreTextView: UIView {
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
context.translateBy(x: 0, y: kScreenHeight)
context.scaleBy(x: 1, y: -1)
context.textMatrix = .identity
let string = "hello world hello world hello world hello world"
// 属性字符串 1 直接设置属性的方式
// guard let attributeString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0) else { return }
// CFAttributedStringReplaceString(attributeString, CFRangeMake(0, 0), string)
// CFAttributedStringSetAttribute(attributeString, CFRangeMake(0, CFStringGetLength(string)), kCTFontAttributeName, CTFontCreateWithName(kCTFontFamilyNameKey, 20, nil))
// 属性字符串 2 直接创建字典的方式
// let dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nil, nil)
// let colorKey = Unmanaged.passRetained(kCTForegroundColorAttributeName).toOpaque()
// let colorValue = Unmanaged.passRetained(UIColor.red.cgColor).toOpaque()
// CFDictionaryAddValue(dict, colorKey, colorValue)
//
// 段落样式
var lineSpacing: CGFloat = 5
var settings: [CTParagraphStyleSetting] = [
CTParagraphStyleSetting(spec: .lineSpacingAdjustment, valueSize: MemoryLayout.size, value: &lineSpacing)
]
let style = CTParagraphStyleCreate(&settings, settings.count)
let dict: [CFString: Any] = [
kCTParagraphStyleAttributeName: style,
kCTForegroundColorAttributeName: UIColor.red
]
let aString = NSAttributedString(string: string, attributes: dict as [NSAttributedString.Key : Any])
guard let attributeString = CFAttributedStringCreateCopy(kCFAllocatorDefault, aString) else { return }
// 整段
let frameSetter = CTFramesetterCreateWithAttributedString(attributeString)
let suggestHeight = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRange(location: 0, length: 0), nil, CGSize(width: 100, height: CGFloat.greatestFiniteMagnitude), nil).height
let path = CGMutablePath()
path.addRect(CGRect(x: 100, y: 100, width: 100, height: suggestHeight))
let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil)
CTFrameDraw(frame, context)
// 单行
// let line = CTLineCreateWithAttributedString(attributeString)
// context.textPosition = CGPoint(x: 100, y: 100)
// CTLineDraw(line, context)
// 手动换行
// var start: CFIndex = 0
// let maxLength: CFIndex = CFStringGetLength(string)
// let typesetter = CTTypesetterCreateWithAttributedString(attributeString)
//
// func drawLine(_ y: CGFloat) {
// let count = CTTypesetterSuggestLineBreak(typesetter, start, 100)
// let line = CTTypesetterCreateLine(typesetter, CFRangeMake(start, count))
// context.textPosition = CGPoint(x: 100, y: y)
// CTLineDraw(line, context)
// start += count
// if start < maxLength {
// drawLine(y + 30)
// }
// }
// drawLine(100)
}
}
参考:https://www.jianshu.com/p/e0277ac633bc
https://www.jianshu.com/p/6a75446fa9fe
https://www.jianshu.com/p/6db3289fb05d
https://www.jianshu.com/p/e52a38e60e7c