coreText自定义文本Label
2014-10-28 09:48
344 查看
coreText自定义富文本Label by Gphone
UILabel是经常使用的一种控件,iOS上的UILabel已经能很好满足一些需求。比如设置对齐方式,换行模式等等。
但如果需求是需要一串字符中不同的字符颜色,字体都单独设置,UILabel就无法满足了。那就自己来做个富文本Label好了。
先创建继承UILabel的AttributedLabel.h,AttributedLabel.m文件,重载UILabeld
-(void)drawTextInRect:(CGRect)rect方法,我们的文本绘制就放在这个函数中。
使用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(0,5)];
[attributedText addAttribute:(NSString*)(kCTForegroundColorAttributeName) value:(id)[[UIColor redColor]CGColor] range:NSMakeRange(6,5)];
CTFontRef font_hello = CTFontCreateWithName((CFStringRef)@“Helvetica”,16,NULL);
CTFontRef font_world = CTFontCreateWithName((CFStringRef)@“GillSans”,20,NULL);
[attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font_hello range:NSMakeRange(0,5)];
[attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font_world range:NSMakeRange(6,5)];
这样,一个包含简单绘制属性的NSMutableAttributedString实例就创建出来了。
接下来就要在drawTextInRect函数中开始绘制了。
普通视图坐标系原点在左上方,而QuartZ绘图的坐标系原点在左下方,所以我们先要调整坐标系。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context,CGAffineTransformIdentity);//重置
CGContextTranslateCTM(context,0,self.bounds.size.height); //y轴高度
CGContextScaleCTM(context,1.0,-1.0);//y轴翻转
好了,可以开始绘制,因为”hello
world”较短,一行就可以放下,那么可以这么绘制
CTLineRef line = CTLineCreateWithAttributedString(attributedText);
CGContextSetTextPosition(context,0,0);
CTLineDraw(line,context);
CFRelease(line);
OK,就这么多搞定。
那如果文本很长,希望换行来显示怎么办?
那我们先要给attributedText添加些关于行相关属性。
下面都是基本的,可以根据自己绘制情况调整,扩充相应的变量。
CTLineBreakMode lineBreakMode = kCTLineBreakByWordWrapping;//换行模式
CTTextAlignment alignment = kCTLeftTextAlignment;//对齐方式
float lineSpacing =2.0;//行间距
CTParagraphStyleSetting paraStyles[3] = {
{.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,3);
[attributedText addAttribute:(NSString*)(kCTParagraphStyleAttributeName) value:(id)style range:NSMakeRange(0,[text length])];
CFRelease(style);
下面就可以绘制了
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path,NULL,self.bounds);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0),path,NULL);
CGContextSetTextPosition(context,0,0);
CTFrameDraw(frame,context);
CFRelease(framesetter);
CFRelease(frame);
这样绘制出来的可以自适应换行了,或者可以做的复杂点,通过上面获取的CTFrameRef
frame来得到CTLineRef绘制
CFArrayRef lines = CTFrameGetLines(frame);
int lineNumber = CFArrayGetCount(lines);
CGPoint lineOrigins[lineNumber];
CTFrameGetLineOrigins(frame,CFRangeMake(0,lineNumber), lineOrigins);
for(int lineIndex = 0;lineIndex <</SPAN> lineNumber;lineIndex++){
CGPoint lineOrigin = lineOrigins[lineIndex];
CTLineRef line = CFArrayGetValueAtIndex(lines,lineIndex);
CGContextSetTextPosition(context,lineOrigin.x,lineOrigin.y);
CTLineDraw(line,context);
}
但这样绘制方法有个问题,就是即使行间距设为0.0(不能为负值)仍是比较分散的。如果希望更进一步控制好行间距,那自己就一行一行计算位置画
float lineHeight = 20; //行高
BOOL drawFlag = YES;//是否绘制
int lineCount = 0;//行数
CFIndex currentIndex = 0;//绘制计数
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,0,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(0,[text length])];
[attributedText addAttribute:(NSString*)(kCTStrokeColorAttributeName) value:(id)[[UIColor whiteColor]CGColor] range:NSMakeRange(0,[text length])];
这样绘制出来的字就细致些。
好了,沿着这条线的内容大致说完,有兴趣的自己敲一敲吧
UILabel是经常使用的一种控件,iOS上的UILabel已经能很好满足一些需求。比如设置对齐方式,换行模式等等。
但如果需求是需要一串字符中不同的字符颜色,字体都单独设置,UILabel就无法满足了。那就自己来做个富文本Label好了。
先创建继承UILabel的AttributedLabel.h,AttributedLabel.m文件,重载UILabeld
-(void)drawTextInRect:(CGRect)rect方法,我们的文本绘制就放在这个函数中。
使用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(0,5)];
[attributedText addAttribute:(NSString*)(kCTForegroundColorAttributeName) value:(id)[[UIColor redColor]CGColor] range:NSMakeRange(6,5)];
CTFontRef font_hello = CTFontCreateWithName((CFStringRef)@“Helvetica”,16,NULL);
CTFontRef font_world = CTFontCreateWithName((CFStringRef)@“GillSans”,20,NULL);
[attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font_hello range:NSMakeRange(0,5)];
[attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font_world range:NSMakeRange(6,5)];
这样,一个包含简单绘制属性的NSMutableAttributedString实例就创建出来了。
接下来就要在drawTextInRect函数中开始绘制了。
普通视图坐标系原点在左上方,而QuartZ绘图的坐标系原点在左下方,所以我们先要调整坐标系。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context,CGAffineTransformIdentity);//重置
CGContextTranslateCTM(context,0,self.bounds.size.height); //y轴高度
CGContextScaleCTM(context,1.0,-1.0);//y轴翻转
好了,可以开始绘制,因为”hello
world”较短,一行就可以放下,那么可以这么绘制
CTLineRef line = CTLineCreateWithAttributedString(attributedText);
CGContextSetTextPosition(context,0,0);
CTLineDraw(line,context);
CFRelease(line);
OK,就这么多搞定。
那如果文本很长,希望换行来显示怎么办?
那我们先要给attributedText添加些关于行相关属性。
下面都是基本的,可以根据自己绘制情况调整,扩充相应的变量。
CTLineBreakMode lineBreakMode = kCTLineBreakByWordWrapping;//换行模式
CTTextAlignment alignment = kCTLeftTextAlignment;//对齐方式
float lineSpacing =2.0;//行间距
CTParagraphStyleSetting paraStyles[3] = {
{.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,3);
[attributedText addAttribute:(NSString*)(kCTParagraphStyleAttributeName) value:(id)style range:NSMakeRange(0,[text length])];
CFRelease(style);
下面就可以绘制了
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path,NULL,self.bounds);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0),path,NULL);
CGContextSetTextPosition(context,0,0);
CTFrameDraw(frame,context);
CFRelease(framesetter);
CFRelease(frame);
这样绘制出来的可以自适应换行了,或者可以做的复杂点,通过上面获取的CTFrameRef
frame来得到CTLineRef绘制
CFArrayRef lines = CTFrameGetLines(frame);
int lineNumber = CFArrayGetCount(lines);
CGPoint lineOrigins[lineNumber];
CTFrameGetLineOrigins(frame,CFRangeMake(0,lineNumber), lineOrigins);
for(int lineIndex = 0;lineIndex <</SPAN> lineNumber;lineIndex++){
CGPoint lineOrigin = lineOrigins[lineIndex];
CTLineRef line = CFArrayGetValueAtIndex(lines,lineIndex);
CGContextSetTextPosition(context,lineOrigin.x,lineOrigin.y);
CTLineDraw(line,context);
}
但这样绘制方法有个问题,就是即使行间距设为0.0(不能为负值)仍是比较分散的。如果希望更进一步控制好行间距,那自己就一行一行计算位置画
float lineHeight = 20; //行高
BOOL drawFlag = YES;//是否绘制
int lineCount = 0;//行数
CFIndex currentIndex = 0;//绘制计数
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,0,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(0,[text length])];
[attributedText addAttribute:(NSString*)(kCTStrokeColorAttributeName) value:(id)[[UIColor whiteColor]CGColor] range:NSMakeRange(0,[text length])];
这样绘制出来的字就细致些。
好了,沿着这条线的内容大致说完,有兴趣的自己敲一敲吧
相关文章推荐
- coreText自定义富文本Label
- coreText自定义富文本Label
- coreText自定义富文本Label by Gphone
- coreText自定义富文本Label by Gphone
- 富文本(TYAttributedLabel 简单,强大的属性文本控件(无需了解CoreText),支持图文混排显示,支持添加链接,image和UIView控件,支持自定义排版显示)
- 总结用CoreText绘制文本时遇到的问题以及解决办法
- Android Dialog自定义处理类textView文本不显示
- 自定义ANDROID中EDITTEXT中的HINT文本的大小
- UI 03 自定义的Label-TextField视图 --- LTView
- Android 自定义TextView实现文本内容自动调整字体大小以适应TextView的大小
- 文本排版之----CoreText
- Android TextView 给文本中指定片段添加自定义点击事件
- 源码(2.2):Coretext文本选择简易阅读器,类似twitter的导航栏
- 自定义Android中EditText中的Hint文本的大小
- 走近Flex组件系列(五):数据组件(Dataehoose,DateFiled)与文本组件(Label,Text)
- R 自定义图例(text、label、colour)
- dev GridView 自定义显示文本 CustomColumnDisplayText
- 自定义TextView,实现图片在文字之前的富文本效果
- tableview 自定义cell 点击cell改变cell中的label.text的字体颜色,cell复用出现问题
- Android 让自定义TextView的drawableLeft与文本一起居中