iOS之UI高级---如何理解图文混排

参考资料:
1.http://www.allenchiang.com/2014/05/28/core-text/
2.唐巧:《iOS进阶》

一、iOS开发中的文字排版

通常我们使用UILabel、UITextField、UITextView在iOS上展示一些我们需要的文字。前者用于简单的展示,后两者可以用于接受用户的输入。通常情况下我们用上述3者展示简单的纯文本,如果我们需要展示图文混排或者稍微带一点排版样式的文字时,我们需要使用更底层的一些技术,比如Text Kit 或者 Core Text

这里写图片描述

上图展示的iOS7的框架层次结构,可以看到基于Core Text的Text Kit为上述3个常用控件提供了技术支持

二、iOS中的CoreText介绍

苹果官方文档的解释:
Core Text is an advanced, low-level technology for laying out text and handling fonts. Core Text works directly with Core Graphics (CG), also known as Quartz, which is the high-speed graphics rendering engine that handles two-dimensional imaging at the lowest level in OS X and iOS.

下面我们跟着这段解释详细了解一下其中的关键字:

①low-level technology:
它直接和底层的CoreGraphics联系,表明它也是一种底层的技术。从中也可以了解它的实现是通过C语言的

②laying out text and handling fonts:
它是一种处理字符的布局引擎(当然,不仅仅是字符),通过这个布局引擎,我们可以实现图文混排、文字链接等UILabel、UITextField控件无法实现的功能

三、CoreText布局引擎结构

首先看一幅图(官方文档中的图):
这里写图片描述

我们可以这么理解字符如何绘制到屏幕上:
①:首先创建一个属性字符串CFAttributedStringRef,它包括了字符的颜色、大小、字体等信息

②:然后创建CTFramesetter,它包括了字符的行间距、缩进、断行方式等
生成的CTFramesetter同时也会唤起一个CTTypesetter,它的作用是将CFAttributedStringRef中的字符转换成对应的字形

③:由①②我们可以生成一个CTFrame,可以想象成一个字符区域。(我们添加一个视图的时候,要设置视图的frame。同理添加字符的时候,也要设置一个frame)
CTFrame中包含CTLine、CTRun。CTLine即每一行,而CTRun是指一行中连续的一段包含同样属性和方向的文字。CTLine中可以有多个CTRun

四、重定制CTRun

通常情况下图文混排,包含了很多内容,还是需要开发者自己做一些事情,对于每个CTRun,我们可以自己设置它的属性。

1.首先,我们看看一个字形是如何定义的:

这里写图片描述

我们要注意的有3个:
①Bounding
②Ascent
③Descent

2.那么图文混排中的文字和颜色到底是如何绘制上去的呢?

①如果我们要绘制文字: 通过以下方法直接绘制CTFrame

void CTFrameDraw(
    CTFrameRef frame,
    CGContextRef context );

②如果我们要绘制图片
其实只是告诉Core Text有一个地方需要占多大的位置,这样系统就会在指定的地方给出了足够的空间。真正的图像绘制其实还是需要我们自己通过Core Graphic来做。
实际操作中,可以:创建空白占位符,并且设置它的CTRunDelegate信息(通过信息判断图片需要的空间大小)
例如:

static CGFloat ascentCallback(void *ref){
    return [(NSNumber*)[(__bridge NSDictionary*)ref objectForKey:@"height"] floatValue];
}

static CGFloat descentCallback(void *ref){
    return 0;
}

static CGFloat widthCallback(void* ref){
    return [(NSNumber*)[(__bridge NSDictionary*)ref objectForKey:@"width"] floatValue];
}

+ (NSAttributedString *)parseImageDataFromNSDictionary:(NSDictionary *)dict
                                                config:(CTFrameParserConfig*)config {
    CTRunDelegateCallbacks callbacks;
    memset(&callbacks, 0, sizeof(CTRunDelegateCallbacks));
    callbacks.version = kCTRunDelegateVersion1;
    callbacks.getAscent = ascentCallback;
    callbacks.getDescent = descentCallback;
    callbacks.getWidth = widthCallback;
    CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (__bridge void *)(dict));

    // 使用0xFFFC作为空白的占位符
    unichar objectReplacementChar = 0xFFFC;
    NSString * content = [NSString stringWithCharacters:&objectReplacementChar length:1];
    NSDictionary * attributes = [self attributesWithConfig:config];
    NSMutableAttributedString * space = [[NSMutableAttributedString alloc] initWithString:content
                                                                               attributes:attributes];
    CFAttributedStringSetAttribute((CFMutableAttributedStringRef)space, CFRangeMake(0, 1),
                                   kCTRunDelegateAttributeName, delegate);
    CFRelease(delegate);
    return space;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值