使用CoreText实现文字环绕图片效果

勿忘初心2018-12-05 13:29

此文已由作者祝栗授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验


众所周知,CoreText作为ios底层的文字渲染和布局框架,可非常便捷地实现自定义文字渲染。而实际应用中,对文字排版可能会有更多的需求,比如,实现文字对图片(或其他元素)的环绕排版,经过分析,这类需求也可以采用CoreText实现。

通常情况下,使用CoreText的一般流程是:

将需要显示的文字及格式转换成NSAttributedString对象,并获得其CoreFoundation层面的CFAttributedString对象

由CFAttributedString生成CTFramesetter对象(文字显示引擎)。

创建CGPath对象,作为绘文字的路径参数;

由CTFramesetter对象,CGPath对象以及文字的CFRange范围,生成一个CTFrame对象(文字显示用对象)。

获得当前图形上下文,对CTFrame做适当地旋转变换,将CTFrame绘于上下文。

代码如下:

CTFrameRef ctframe = NULL;

CTFramesetterRef frs = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);

CGMutablePathRef columnPath = CGPathCreateMutable();

CGPathAddRect(columnPath, NULL ,CGRectMake(0 , 0 ,self.bounds.size.width , self.bounds.size.height));

ctframe = CTFramesetterCreateFrame(frs,CFRangeMake(0, 0), columnPath , NULL);

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetTextMatrix(context , CGAffineTransformIdentity);

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

CGContextScaleCTM(context, 1.0 ,-1.0);

CTFrameDraw(ctframe,context);

CGPathRelease(columnPath);

CFRelease(frs);

UIGraphicsPushContext(context);


为了实现文字环绕图片的效果,关键就在获得正确的CGPath对象。从CGPath的定义中我们了解,路径定义了一个或多个形状,或是子路径。一个子路径可由直线,曲线,或者同时由两者构成。它可以是开放的,也可以是闭合的。一个子路径可以是简单的形状,如线、圆、矩形、星形;也可以是复杂的形状,如山脉的轮廓或者是涂鸦。理论上我们可以创建任何复杂程度的路径。


对于一般的文字环绕效果,基本路径还是比较简单的。


文字路径是一个闭合空间。起始点为(100,0),经过的路径分别是(300,0), (300,200), (0,200), (0,100),(100,100),(100,0),通过这个路径分析,可以实现以下的代码:

UIBezierPath *path = [UIBezierPath bezierPath];

[path moveToPoint:CGPointMake(100.0,0.0)];

[path addLineToPoint:CGPointMake(300.0,0.0)];

[path addLineToPoint:CGPointMake(300.0,200.0)];

[path addLineToPoint:CGPointMake(0.0,200.0)];

[path addLineToPoint:CGPointMake(0.0,100.0)];

[path addLineToPoint:CGPointMake(100.0,100.0)];

[path addLineToPoint:CGPointMake(100.0,0.0)];

[path closePath];

CTFrameRef ctframe = CTFramesetterCreateFrame(frs, CFRangeMake(0, 0), path.CGPath, NULL);


当然,如果我们要实现的是像下面那张图那样的效果,该怎么做呢?


我没有实际尝试过,但大致考虑的方案是否可以是这样:

1. 以某种图像识别算法获得图片的边缘点的点阵数据

2. addLineToPoint到每个点

3. 形成CGPath,绘到图形上下文

如果有哪位大侠尝试实现一下,可以形成一个通用的文字环绕模块,其意义也是非同小可的。


免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

更多网易技术、产品、运营经验分享请点击