来自:http://blog.sina.com.cn/s/blog_7c8dc2d50101lbb1.html

使用coreText进行文本绘制,需要在工程中添加CoreText.framework,然后在AttributedLabel.m里import就可以使用了。coreText负责绘制,那绘制的内容和属性则要靠NSAttributedString来存储,如果属性具有不确定性,可以使用NSMutableAttributedString,方便后面添加属性。

先来看下如何创建一个具有两个颜色,两种字体的“hello world”的NSMutableAttributedString实例。

NSString *text = @"hello word";

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];

[attributedText addAttribute:(NSString*)(kCTForegroundColorAttributeName) value:(id)[[UIColor blueColor]CGColor] range:NSMakeRange(,)];

[attributedText addAttribute:(NSString*)(kCTForegroundColorAttributeName) value:(id)[[UIColor redColor]CGColor] range:NSMakeRange(,)];

CTFontRef  font_hello = CTFontCreateWithName((CFStringRef)@"Helvetica",,NULL);

CTFontRef  font_world = CTFontCreateWithName((CFStringRef)@"GillSans",,NULL);

[attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font_hello range:NSMakeRange(,)];

[attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font_world range:NSMakeRange(,)];

这样,一个包含简单绘制属性的NSMutableAttributedString实例就创建出来了。

接下来就要在drawTextInRect函数中开始绘制了。

普通视图坐标系原点在左上方,而QuartZ绘图的坐标系原点在左下方,所以我们先要调整坐标系。

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetTextMatrix(context,CGAffineTransformIdentity);//重置

CGContextTranslateCTM(context,,self.bounds.size.height); //y轴高度

CGContextScaleCTM(context,1.0,-1.0);//y轴翻转

好了,可以开始绘制,因为"hello world"较短,一行就可以放下,那么可以这么绘制

CTLineRef line = CTLineCreateWithAttributedString(attributedText);

CGContextSetTextPosition(context,,);

CTLineDraw(line,context);

CFRelease(line);

OK,就这么多搞定。

那如果文本很长,希望换行来显示怎么办?

那我们先要给attributedText添加些关于行相关属性。

下面都是基本的,可以根据自己绘制情况调整,扩充相应的变量。

CTLineBreakMode lineBreakMode = kCTLineBreakByWordWrapping;//换行模式

CTTextAlignment alignment = kCTLeftTextAlignment;//对齐方式

float lineSpacing =2.0;//行间距

CTParagraphStyleSetting paraStyles[] = {

{.spec = kCTParagraphStyleSpecifierLineBreakMode,.valueSize = sizeof(CTLineBreakMode), .value = (const void*)&lineBreakMode},

{.spec = kCTParagraphStyleSpecifierAlignment,.valueSize = sizeof(CTTextAlignment), .value = (const void*)&alignment},

{.spec = kCTParagraphStyleSpecifierLineSpacing,.valueSize = sizeof(CGFloat), .value = (const void*)&lineSpacing},

};

CTParagraphStyleRef style = CTParagraphStyleCreate(paraStyles,);

[attributedText addAttribute:(NSString*)(kCTParagraphStyleAttributeName) value:(id)style range:NSMakeRange(,[text length])];

CFRelease(style);
下面就可以绘制了
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);

CGMutablePathRef path = CGPathCreateMutable();

CGPathAddRect(path,NULL,self.bounds);

CTFrameRef frame = CTFramesetterCreateFrame(framesetter,CFRangeMake(,),path,NULL);

CGContextSetTextPosition(context,,);

CTFrameDraw(frame,context);

CFRelease(framesetter);

CFRelease(frame);

这样绘制出来的可以自适应换行了,或者可以做的复杂点,通过上面获取的CTFrameRef frame来得到CTLineRef绘制

CFArrayRef lines = CTFrameGetLines(frame);

int lineNumber = CFArrayGetCount(lines);

CGPoint lineOrigins[lineNumber];

CTFrameGetLineOrigins(frame,CFRangeMake(,lineNumber), lineOrigins);

for(int lineIndex = ;lineIndex < lineNumber;lineIndex++){

CGPoint lineOrigin = lineOrigins[lineIndex];

CTLineRef line = CFArrayGetValueAtIndex(lines,lineIndex);

CGContextSetTextPosition(context,lineOrigin.x,lineOrigin.y);

CTLineDraw(line,context);

}

但这样绘制方法有个问题,就是即使行间距设为0.0(不能为负值)仍是比较分散的。如果希望更进一步控制好行间距,那自己就一行一行计算位置画

float lineHeight = ; //行高

BOOL drawFlag = YES;//是否绘制

int lineCount = ;//行数

CFIndex currentIndex = ;//绘制计数

CTTypesetterRef typeSetter = CTTypesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);

float fontAscender = MAX(font_hello.ascender,font_world.ascender);

float y = self.bounds.origin.y+self.bounds.size.height-fontAscender;

while(drawFlag)

{

CFIndex lineLength = CTTypesetterSuggestLineBreak(typeSetter,currentIndex,self.bounds.size.width);

CFRange lineRange = CFRangeMake(currentIndex,lineLength);

CTLineRef line = CTTypesetterCreateLine(typeSetter,lineRange);

float x = CTLineGetPenOffsetForFlush(line,,self.bounds.size.width);

CGContextSetTextPosition(context,x,y);

CTLineDraw(line,context);

if(currentIndex + lineLength >= [text length]){

drawFlag = NO;

}

CFRelease(line);

count++;

y -=lineHeight;

currentIndex += lineLength;

}

CFRelease(typeSetter);

到这里的时候,又有个问题,就是用同样的字体和字号,绘制的字总是会比UILabel显示的粗些。

查看kCTStrokeWidthAttributeName属性发现默认已经为0.0,但这个值是可以为负值,那就变通的解决这个问题。

在attributedText里添加两个属性值

CGFloat widthValue = -1.0;

CFNumberRef strokeWidth = CFNumberCreate(NULL,kCFNumberFloatType,&widthValue);

[attributedText addAttribute:(NSString*)(kCTStrokeWidthAttributeName) value:(id)strokeWidth range:NSMakeRange(,[text length])];

[attributedText addAttribute:(NSString*)(kCTStrokeColorAttributeName) value:(id)[[UIColor whiteColor]CGColor] range:NSMakeRange(,[text length])];

这样绘制出来的字就细致些

CoreText的绘制流程-转的更多相关文章

  1. 深入理解 Android 之 View 的绘制流程

    概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...

  2. Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  3. Android中View绘制流程以及invalidate()等相关方法分析

    [原文]http://blog.csdn.net/qinjuning 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简 ...

  4. Android视图绘制流程完全解析,带你一步步深入了解View(二)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/16330267 在上一篇文章中,我带着大家一起剖析了一下LayoutInflater ...

  5. UE3:SkeletalMesh的绘制流程

    [目标] SkeletalMesh的绘制流程 [思路] 1 顶点缓冲流 静态数据流向 动态数据流向(紫红色箭头) 2 FGPUSkinVertexFactory.ShaderDataType.Bone ...

  6. 自定义View_1_关于View,ViewGroup的测量和绘制流程

    自定义View(1) ------ 关于View,ViewGroup的测量和绘制流程 在Android当中,自定义控件属于比较高级的知识体系,今天我们就一起研究研究关于自定义View的那点事,看看它到 ...

  7. View (三) 视图绘制流程完全解析

    相 信每个Android程序员都知道,我们每天的开发工作当中都在不停地跟View打交道,Android中的任何一个布局.任何一个控件其实都是直接或间 接继承自View的,如TextView.Butto ...

  8. OpenGL ES学习笔记(一)——基本用法、绘制流程与着色器编译

    首先声明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. 在Android.iOS等移动平台上 ...

  9. Android View绘制流程

    框架分析 在之前的下拉刷新中,小结过触屏消息先到WindowManagerService(Wms)然后顺次传递给ViewRoot(派生自Handler),经decor view到Activity再传递 ...

随机推荐

  1. VC++ VS2010 error LNK1123 转换到 COFF 期间失败 怎么办

    1 无法输出Hello world   2 点击项目-属性,打开属性页   3 配置属性-清单工具-输入和输出-嵌入清单改成否   4 找出计算机中的所有cvtres.exe,删掉早期的,只留最新版的 ...

  2. VM Workstation的Unity Mode有什么用

    正常情况下,如果我启动了一个VM Workstaion的虚拟机,比如是一个Linux系统,并且没运行任何软件,进入Unity mode之后,我真实系统的左下角会有一个虚拟机的图标 点击这个图标可以打开 ...

  3. PHPCMS中GET标签概述、 get 标签语法、get 标签创建工具、get 调用本系统演示样例、get 调用其它系统演示样例

    一.get 标签概述 通俗来讲,get 标签是Phpcms定义的能直接调用数据库里面内容的简单化.友好化代码,她可调用本系统和外部数据,仅仅有你对SQL有一定的了解,她就是你的绝世好剑!也就是适合熟悉 ...

  4. Redis管理各类型存储数据命令

    >>>字符串 1 SET key value 设置指定 key 的值 2 GET key 获取指定 key 的值. 3 GETRANGE key start end 返回 key 中 ...

  5. ubuntu hadoop伪分布式部署

    环境 ubuntu hadoop2.8.1 java1.8 1.配置java1.8 2.配置ssh免密登录 3.hadoop配置 环境变量 配置hadoop环境文件hadoop-env.sh core ...

  6. pat1043:输出PATest

    https://www.patest.cn/contests/pat-b-practise/1043 #include "stdio.h" int main() { int i, ...

  7. 架构师基本功:SOA

    (以下内容为个人理解,可能不够全面和准确) SOA (service-oriented architecture),面向服务的架构 啥是SOA?网上的解释,玄而又玄.俺说点人话,也许不准确,但现阶段我 ...

  8. Oracle可插拔数据库的jdbc连接串写法

    我在服务器上部署某个第三方系统的数据库的时候,服务器数据库版本为oracle 12c.我采用的方式是新建了一个实例.访问正常. 后来项目的负责人告诉我,oracle12C支持所谓的可插拔数据库.可插拔 ...

  9. xcode10的那些事

    前言 这里主要介绍一下Xcode10 版本主要更新的内容.随着iOS12的发布,Xcode10已经可以从Mac App Store下载.Xcode10包含了iOS12.watchOS 5.macOS1 ...

  10. 交换分区 在dd命令执行期间 top 其消耗系统约14%的cpu,而mem占比约为0

    [资源不友好代码] from pyltp import * d_dir = '/usr/local/ltp_data_v3.4.0/' def gen_one_sentence_part(paragr ...