[转] 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端研发负责人多年的经验,从如何优化现有代码的角度出发,深度分析如何创 ...
随机推荐
- Nodejs学习笔记(三)—模块
简介及资料 通过Node.js的官方API可以看到Node.js本身提供了很多核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,可以require('模块名') ...
- 【.Net】含Unicode的字符串截断 VB.NET C#
Function AnsiLeftB(ByVal strArg As String, ByVal arg1 As Integer) As String Dim unicodeEncoding As E ...
- Beta阶段——Scrum 冲刺博客第二天
一.当天站立式会议照片一张 二.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中 昨天已完成的工作 实现对index界面的重新制作,变成了原来的main界面,直接在该界面输入 ...
- 个人总结(Alpha阶段)
Alpha总结 我们在alpha 结束之后, 每位写一个博客, 回顾并总结自己的alpha 过程,哪些方面做的好的,哪些方面做得不足需要改进的 提出问题 同时,大家一定会在过程中产生了很多问题, 结合 ...
- JavaScript 常用的小功能集合
1. 得到当前用户使用的浏览器的内核版本 function getExplorer(){ var browser = ""; var explorer = window.navig ...
- Ubuntu18---VMware虚拟机中Ubuntu18.04系统,开机输入密码后无响应黑屏
系统崩坏了,重装过几次,这次决定不充装了. 搜索大神解决方案后,了解到是图形界面程序损坏,可能是在更新内核或者安装软件的时候,把与xorg相关的文件给清除了. 解决方案如下: 1.登录系统进入,黑屏后 ...
- WCF webHttpBinding协议上传接收文件
一般情况下wcf用webHttpBinding协议最多的场景就是前后端Json交互,会比较轻量级. 接收上传的文件也可以,不过要自己解析处理. 前端HTML很简单: <input type=&q ...
- Navbar和Tabbar常用设置
1.navBar [self.navigationController.navigationBar setBackgroundImage:navBarImage forBarMetrics:UIBar ...
- fuzhou 1075 分解素因子
Problem 1075 分解素因子 Accept: 1331 Submit: 2523Time Limit: 1000 mSec Memory Limit : 32768 KB Prob ...
- 使用css实现炫酷的横屏滚动效果
炫酷的横屏滚动效果css实现 DEMO: https://codepen.io/kobako/pen/BxVLLm 我们对滚动条都不陌生.平时浏览的网页,进度条通常是垂直方向的,内容从上往下排列.但是 ...