您的位置:首页 > 产品设计 > UI/UE

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

2015-11-12 16:19 645 查看
参考资料:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios ui