[转] iOS文字排版(CoreText)那些事儿
文章转载自 http://www.cocoachina.com/applenews/devnews/2014/0521/8504.html
iOS文字排版(CoreText)那些事儿


转自阿毛的蛋疼地
第一次比较深入接触iOS文字排版相关内容是在12年底,实现某IM项目聊天内容的图文混排,照着nimbus的AttributedLabel和Raywenderlish上的这篇文章《Core Text Tutorial for iOS: Making a Magazine App》改出了一个比较适用于聊天内容展现的图文混排(文字和表情)控件。






- - (void)appendAttachment: (M80AttributedLabelAttachment *)attachment
- {
- attachment.fontAscent = _fontAscent;
- attachment.fontDescent = _fontDescent;
- unichar objectReplacementChar = 0xFFFC;
- NSString *objectReplacementString = [NSString stringWithCharacters:&objectReplacementChar length:1];
- NSMutableAttributedString *attachText = [[NSMutableAttributedString alloc]initWithString:objectReplacementString];
- CTRunDelegateCallbacks callbacks;
- callbacks.version = kCTRunDelegateVersion1;
- callbacks.getAscent = ascentCallback;
- callbacks.getDescent = descentCallback;
- callbacks.getWidth = widthCallback;
- callbacks.dealloc = deallocCallback;
- CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (void *)attachment);
- NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)delegate,kCTRunDelegateAttributeName, nil];
- [attachText setAttributes:attr range:NSMakeRange(0, 1)];
- CFRelease(delegate);
- [_attachments addObject:attachment];
- [self appendAttributedText:attachText];
- }
- CGFloat ascentCallback(void *ref)
- {
- M80AttributedLabelAttachment *image = (__bridge M80AttributedLabelAttachment *)ref;
- CGFloat ascent = 0;
- CGFloat height = [image boxSize].height;
- switch (image.alignment)
- {
- case M80ImageAlignmentTop:
- ascent = image.fontAscent;
- break;
- case M80ImageAlignmentCenter:
- {
- CGFloat fontAscent = image.fontAscent;
- CGFloat fontDescent = image.fontDescent;
- CGFloat baseLine = (fontAscent + fontDescent) / 2 - fontDescent;
- ascent = height / 2 + baseLine;
- }
- break;
- case M80ImageAlignmentBottom:
- ascent = height - image.fontDescent;
- break;
- default:
- break;
- }
- return ascent;
- }
- CGFloat descentCallback(void *ref)
- {
- M80AttributedLabelAttachment *image = (__bridge M80AttributedLabelAttachment *)ref;
- CGFloat descent = 0;
- CGFloat height = [image boxSize].height;
- switch (image.alignment)
- {
- case M80ImageAlignmentTop:
- {
- descent = height - image.fontAscent;
- break;
- }
- case M80ImageAlignmentCenter:
- {
- CGFloat fontAscent = image.fontAscent;
- CGFloat fontDescent = image.fontDescent;
- CGFloat baseLine = (fontAscent + fontDescent) / 2 - fontDescent;
- descent = height / 2 - baseLine;
- }
- break;
- case M80ImageAlignmentBottom:
- {
- descent = image.fontDescent;
- break;
- }
- default:
- break;
- }
- return descent;
- }
- CGFloat widthCallback(void* ref)
- {
- M80AttributedLabelAttachment *image = (__bridge M80AttributedLabelAttachment *)ref;
- return [image boxSize].width;
- }
- - (void)drawAttachments
- {
- if ([_attachments count] == 0)
- {
- return;
- }
- CGContextRef ctx = UIGraphicsGetCurrentContext();
- if (ctx == nil)
- {
- return;
- }
- CFArrayRef lines = CTFrameGetLines(_textFrame);
- CFIndex lineCount = CFArrayGetCount(lines);
- CGPoint lineOrigins[lineCount];
- CTFrameGetLineOrigins(_textFrame, CFRangeMake(0, 0), lineOrigins);
- NSInteger numberOfLines = [self numberOfDisplayedLines];
- for (CFIndex i = 0; i < numberOfLines; i++)
- {
- CTLineRef line = CFArrayGetValueAtIndex(lines, i);
- CFArrayRef runs = CTLineGetGlyphRuns(line);
- CFIndex runCount = CFArrayGetCount(runs);
- CGPoint lineOrigin = lineOrigins[i];
- CGFloat lineAscent;
- CGFloat lineDescent;
- CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, NULL);
- CGFloat lineHeight = lineAscent + lineDescent;
- CGFloat lineBottomY = lineOrigin.y - lineDescent;
- // Iterate through each of the "runs" (i.e. a chunk of text) and find the runs that
- // intersect with the range.
- for (CFIndex k = 0; k < runCount; k++)
- {
- CTRunRef run = CFArrayGetValueAtIndex(runs, k);
- NSDictionary *runAttributes = (NSDictionary *)CTRunGetAttributes(run);
- CTRunDelegateRef delegate = (__bridge CTRunDelegateRef)[runAttributes valueForKey:(id)kCTRunDelegateAttributeName];
- if (nil == delegate)
- {
- continue;
- }
- M80AttributedLabelAttachment* attributedImage = (M80AttributedLabelAttachment *)CTRunDelegateGetRefCon(delegate);
- CGFloat ascent = 0.0f;
- CGFloat descent = 0.0f;
- CGFloat width = (CGFloat)CTRunGetTypographicBounds(run,
- CFRangeMake(0, 0),
- &ascent,
- &descent,
- NULL);
- CGFloat imageBoxHeight = [attributedImage boxSize].height;
- CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, nil);
- CGFloat imageBoxOriginY = 0.0f;
- switch (attributedImage.alignment)
- {
- case M80ImageAlignmentTop:
- imageBoxOriginY = lineBottomY + (lineHeight - imageBoxHeight);
- break;
- case M80ImageAlignmentCenter:
- imageBoxOriginY = lineBottomY + (lineHeight - imageBoxHeight) / 2.0;
- break;
- case M80ImageAlignmentBottom:
- imageBoxOriginY = lineBottomY;
- break;
- }
- CGRect rect = CGRectMake(lineOrigin.x + xOffset, imageBoxOriginY, width, imageBoxHeight);
- UIEdgeInsets flippedMargins = attributedImage.margin;
- CGFloat top = flippedMargins.top;
- flippedMargins.top = flippedMargins.bottom;
- flippedMargins.bottom = top;
- CGRect attatchmentRect = UIEdgeInsetsInsetRect(rect, flippedMargins);
- id content = attributedImage.content;
- if ([content isKindOfClass:[UIImage class]])
- {
- CGContextDrawImage(ctx, attatchmentRect, ((UIImage *)content).CGImage);
- }
- else if ([content isKindOfClass:[UIView class]])
- {
- UIView *view = (UIView *)content;
- if (view.superview == nil)
- {
- [self addSubview:view];
- }
- CGRect viewFrame = CGRectMake(attatchmentRect.origin.x,
- self.bounds.size.height - attatchmentRect.origin.y - attatchmentRect.size.height,
- attatchmentRect.size.width,
- attatchmentRect.size.height);
- [view setFrame:viewFrame];
- }
- else
- {
- NSLog(@"Attachment Content Not Supported %@",content);
- }
- }
- }
- }
[转] iOS文字排版(CoreText)那些事儿的更多相关文章
- iOS:基于CoreText的排版引擎
一.CoreText的简介 CoreText是用于处理文字和字体的底层技术.它直接和Core Graphics(又被称为Quartz)打交道.Quartz是一个2D图形渲染引擎,能够处理OSX和iOS ...
- iOS开发-UITextView文字排版
UITextView文本排版 1.配置NSMutableParagraphStyle NSMutableParagraphStyle *MParaStyle = [[NSMutableParagrap ...
- (转)iOS7界面设计规范(10) - UI基础 - 文字排版与配色
明天就是周四了.貌似前几天还在恨周一呢.话说今天几乎开了一整天的会,正经事情没做多少:这种感觉比一整天从早到晚12个小时的忙碌于一件事情还要让人感到疲惫的对叭?那今天的iOS7设计规范更新又是一篇很简 ...
- amazeui学习笔记--css(基本样式3)--文字排版Typography
amazeui学习笔记--css(基本样式3)--文字排版Typography 一.总结 1.字体:amaze默认非 衬线字体(sans-serif) 2.引用块blockquote和定义列表:引用块 ...
- OpenJudge计算概论-文字排版
/*====================================================================== 文字排版 总时间限制: 1000ms 内存限制: 65 ...
- div介绍 盒子模型边框属性 CSS初始化 文字排版 边框调整 溢出
今天学习的div,了解了div是干什么用的掌握了什么是盒子模型,以及div的外边距内边距以及边框,运用div和CSS给文字排版,利用边框的来做图像,div溢出的处理 CSS初始化: 精确排版的时候用这 ...
- 【html】文字排版
Web开发过程中文字排版,默认的情况下,行末的长单词会撑开容器. 我们想要的是(像word一样.能够自动换行.既不撑大容器.也不强制拆开行末单词.并且不会隐藏行末单词的多余字母) ①不能撑开容器 ②完 ...
- bootstrap世界探索1——山川河流(文字排版)
世界到底是什么?其实世界很简单,正所谓一花一世界,一树一菩提,世界就在我们身边.造物神是伟大的,在我看来无论是HTML,css,js都可以看作是一个世界,但是他们是构成宏观世界不可或缺的,正如IU框架 ...
- iOS App开发的那些事儿2:如何搭建合适的框架
<iOS App开发的那些事儿>系列文章从更宏观的角度出发,不仅仅局限于具体某个功能.界面的实现,而是结合网易云信iOS端研发负责人多年的经验,从如何优化现有代码的角度出发,深度分析如何创 ...
随机推荐
- 【好书分享】容器网络到kubernetes网络
Nginx 公司的 Michael Hausenblas 发布了一本关于 docker 和 kubernetes 中的容器网络的小册子.这份资料一共 72 页,是大家由浅入深的了解 Docker 和 ...
- android学习-数据存储(一)-----SQLite源码分析
分析SQLiteDatabase.java,SQLiteStatement.java,SQLiteSession.java,SQLiteConnectionPool.java,SQLiteConnec ...
- python单元测试pytest
1.pytest简介 pytest是Python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高. 执行测试过程中可以将某些测试 ...
- WPF样式动画Trigger.EnterActions和Trigger.ExitActions(ExitActions其实可以不做任何事情)
这是一个鼠标移入后,控件往左移动的动画: <Style TargetType="{x:Type StackPanel}"> <Setter Property=&q ...
- Mahout实战---编写自己的相似度计算方法
Mahout本身提供了很多的相似度计算方法,如PCC,COS等.但是当需要验证自己想出来的相似度计算公式是否是好的,这时候需要自己实现相似度类.研究了Mahout-core-0.9.jar的源码后,自 ...
- free函数使用时的注意事项。
free函数是我们在写C语言程序时常用的函数,但是使用时需要注意,一不小心很肯能会引起吐核. 注意:free函数与malloc()函数配对使用,malloc函数释放申请的动态内存.对于free(p)这 ...
- 自学C Primer Plus时还没想明白的问题
2016年11月24日 1. 计算机中两个浮点数怎样进行加法运算.2. 为什么计算机在计算时存在损失精度的可能3. 无符号数和有符号数的运算是怎样的4. printf中使用格式控制符的截断问题,比如% ...
- fiddler工作原理和设置代理问题
1,什么是Fiddler Fiddler是一个http协议调试代理工具,它能够记录客户端和服务器之间的所有 HTTP请求,可以针对特定的HTTP请求,分析请求数据.设置断点.调试web应用.修改请求的 ...
- [九省联考 2018]秘密袭击coat
Description 题库链接 给出一棵 \(n\) 个点的树,每个点有点权.求所有联通块的权值 \(k\) 大和,对 \(64123\) 取模. \(1\leq n,k\leq 1666\) So ...
- JavaScript 函数全局变量定义
在 JavaScript 中, 作用域 影响着变量的作用范围.在函数外定义的变量具有 全局 作用域.这意味着,具有全局作用域的变量可以在代码的任何地方被调用. 没有使用var关键字定义的变量,会被自动 ...