背景:我开始我的项目在iOS 5中,并建立了一个漂亮的按钮,层。 我添加了一个textLayer到按钮并且使用以下代码它中心:
float textLayerVerticlePadding = ((self.bounds.size.height - fontSize) /2);
textLayer = [[CATextLayer alloc]init];
[textLayer setFrame:CGRectOffset(self.bounds, 0, textLayerVerticlePadding)];
它的伟大工程,并期待死点,直到iOS 6中。
问题:iOS 6中加入结合的最上和最在textLayer文本之间的空间(填充)。 此扰乱上述计算。 有没有一种方法,以确保iOS 6的不? 因为我想支持的iOS 5和6(对于那些谁喜欢谷歌地图)。
图片:
这一个是iOS 5及红色是textLayer的背景(使它更加明显)
而这一次的iOS 6
更新:虽然下面我敢肯定,所有的答案都以自己的方式是正确的,我发现t0rst最简单的方法后才能执行此。 HelveticaNeue
留下了一点空间两者的iOS5和iOS6的,不像Helvetica
这让在iOS5的顶部和小空间iOS6的没有空间。
更新2:与它玩耍了多一点,并且发现了小空间的大小。 没有进入细节,空间是您的字体大小的1/6。 因此,为了弥补它,我写
float textLayerVerticlePadding = ((self.bounds.size.height - fontSize) /2) - (fontSize/6);
[textLayer setFrame:CGRectOffset(self.bounds, 0, textLayerVerticlePadding)];
与该代码,我得到一个死点每次。 请注意,这仅与测试HelveticaNeue-Bold
上的iOS5和iOS6的。 我不能说别的。
在IOS 5和之前,在所述第一基线CATextLayer
总是从边界由从得到的上升顶向下定位CTLineGetTypographicBounds
当通过了CTLine
与串用于第一线制成。
在iOS 6中,这并不适用于所有的字体真了。 因此,当你定位CATextLayer
你再也不能可靠地决定把它放在哪里得到正确的视觉对准。 或者,你可以吗? ...
首先,顺便说一句:努力工作,出来的时候CATextLayer
iOS 5中的定位特性前一阵子,我想终于发现,从提升使用前盖的高度,从UIFont伸等的所有组合CTLineGetTypographicBounds
是我需要的人。 在这个过程中,我发现一)从上升UIFont ascender
, CTFontGetAscent
和CTLineGetTypographicBounds
对某些字体不一致,和b)的上升经常是奇怪-无论是裁剪的口音或离开的方式上面的空间。 该解决方案的)是知道要使用的值。 是不是真的到B以外的解决方案),比抵消离开上述足够的空间CATextLayer
范围,如果它有可能你将有会被切去口音。
返回到iOS 6,如果你避免最坏违规字体(如6.0,并可能随时更改),你仍然可以做的程序化定位CATextLayer
与字体的其余部分。 罪犯是:AcademyEngravedLetPlain, 快递 ,和HoeflerText 帕拉提诺 -视觉,这些家庭位置正确地(即,没有削波)在CATextLayer
,但没有的三个上升源给你其中基线被放置的可用指示。 黑体和.HelveticaNeueUI(又名系统字体)家庭与给出的上升基线正确位置UIFont ascender
,但其他上升源使用的不是。
从测试的一些例子我做到了。 示例文本是用不同的颜色绘制三次。 坐标原点是灰色框的左上角。 黑白文本被绘制CTLineDraw
向下偏移从上升CTLineGetTypographicBounds
; 透明的红色是通过绘制CATextLayer
与边界等于灰色方块; 透明的蓝色被吸入与UIKit
NSString
此外drawAtPoint:withFont:
在灰色方块的起源,并与定位UIFont
。
1)一种表现良好的字体,铜版光强。 这三个样本是一致的,给人栗色,并且这意味着攀登足够近的来自所有来源相同。 相同的iOS 5和6。
2)下的iOS 5, 快递 CATextLayer
位置文本太高(红色),但CTLineDraw
从上升CTLineGetTypographicBounds
(黑色)匹配CATextLayer
定位-所以我们可以把从那里正确。 NSString drawAtPoint:withFont:
蓝色)放置文本而不削波。 ( 黑体和.HelveticaNeueUI这样的表现在IOS 6)
3)的iOS 6下快递 CATextLayer
(红色)现在放置文本,以便它不会被截断,但定位不再与从上升CTLineGetTypographicBounds
(黑色)或UIFont
中使用上升器NSString drawAtPoint:withFont:
蓝色)。 这是不能用于程序化的定位。 (AcademyEngravedLetPlain,HoeflerText和帕拉提诺也这样的表现在IOS 6)
希望这有助于避免一些浪费时间,我所经历的时间,如果你想深一点沾,有这样一出戏:
- (NSString*)reportInconsistentFontAscents
{
NSMutableString* results;
NSMutableArray* fontNameArray;
CGFloat fontSize = 28;
NSString* fn;
NSString* sample = @"Éa3Çy";
CFRange range;
NSMutableAttributedString* mas;
UIFont* uifont;
CTFontRef ctfont;
CTLineRef ctline;
CGFloat uif_ascent;
CGFloat ctfont_ascent;
CGFloat ctline_ascent;
results = [NSMutableString stringWithCapacity: 10000];
mas = [[NSMutableAttributedString alloc] initWithString: sample];
range.location = 0, range.length = [sample length];
fontNameArray = [NSMutableArray arrayWithCapacity: 250];
for (fn in [UIFont familyNames])
[fontNameArray addObjectsFromArray: [UIFont fontNamesForFamilyName: fn]];
[fontNameArray sortUsingSelector: @selector(localizedCaseInsensitiveCompare:)];
[fontNameArray addObject: [UIFont systemFontOfSize: fontSize].fontName];
[fontNameArray addObject: [UIFont italicSystemFontOfSize: fontSize].fontName];
[fontNameArray addObject: [UIFont boldSystemFontOfSize: fontSize].fontName];
[results appendString: @"Font name\tUIFA\tCTFA\tCTLA"];
for (fn in fontNameArray)
{
uifont = [UIFont fontWithName: fn size: fontSize];
uif_ascent = uifont.ascender;
ctfont = CTFontCreateWithName((CFStringRef)fn, fontSize, NULL);
ctfont_ascent = CTFontGetAscent(ctfont);
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)mas, range, kCTFontAttributeName, ctfont);
ctline = CTLineCreateWithAttributedString((CFAttributedStringRef)mas);
ctline_ascent = 0;
CTLineGetTypographicBounds(ctline, &ctline_ascent, 0, 0);
[results appendFormat: @"\n%@\t%.3f\t%.3f\t%.3f", fn, uif_ascent, ctfont_ascent, ctline_ascent];
if (fabsf(uif_ascent - ctfont_ascent) >= .5f // >.5 can round to pixel diffs in display
|| fabsf(uif_ascent - ctline_ascent) >= .5f)
[results appendString: @"\t*****"];
CFRelease(ctline);
CFRelease(ctfont);
}
[mas release];
return results;
}
t0rst的回答可以帮助我。 我想,大写高度和X字高是关键。
CATextLayer *mytextLayer = [CATextLayer layer];
CGFloat fontSize = 30;
UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];
mytextLayer.font = (__bridge CFTypeRef)(boldFont.fontName);
mytextLayer.fontSize = fontSize;
CGFloat offsetY = 0;
//if system version is grater than 6
if(([[[UIDevice currentDevice] systemVersion] compare:@"6" options:NSNumericSearch] == NSOrderedDescending)){
offsetY = -(boldFont.capHeight - boldFont.xHeight);
}
//you have to set textX, textY, textWidth
mytextLayer.frame = CGRectMake(textX, textY + offsetY, textWidth, fontSize);
威乐我在等待最终的解决方案,我研究过RTLabel和TTTAttributedLabel,并做了一个简单的类来绘制一个CALayer的文本作为史蒂夫建议。 希望它能帮助,请不要犹豫,指出我所做的任何错误。
CustomTextLayer.h
#import <QuartzCore/QuartzCore.h>
@interface CustomTextLayer : CALayer {
NSString *_text;
UIColor *_textColor;
NSString *_font;
float _fontSize;
UIColor *_strokeColor;
float _strokeWidth;
CTTextAlignment _textAlignment;
int _lineBreakMode;
float _suggestHeight;
}
-(float) suggestedHeightForWidth:(float) width;
@property (nonatomic, retain) NSString *text;
@property (nonatomic, retain) UIColor *textColor;
@property (nonatomic, retain) NSString *font;
@property (nonatomic, assign) float fontSize;
@property (nonatomic, retain) UIColor *strokeColor;
@property (nonatomic, assign) float strokeWidth;
@property (nonatomic, assign) CTTextAlignment textAlignment;
@end
CustomTextLayer.m
#import <CoreText/CoreText.h>
#import "CustomTextLayer.h"
@implementation CustomTextLayer
@synthesize text = _text, textColor = _textColor;
@synthesize font = _font, fontSize = _fontSize;
@synthesize strokeColor = _strokeColor, strokeWidth = _strokeWidth;
@synthesize textAlignment = _textAlignment;
-(id) init {
if (self = [super init]) {
_text = @"";
_textColor = [UIColor blackColor];
_font = @"Helvetica";
_fontSize = 12;
_strokeColor = [UIColor whiteColor];
_strokeWidth = 0.0;
_textAlignment = kCTLeftTextAlignment;
_lineBreakMode = kCTLineBreakByWordWrapping;
}
return self;
}
-(void) dealloc {
[_text release];
[_textColor release];
[_font release];
[_strokeColor release];
[super dealloc];
}
-(void) setText:(NSString *)text {
[_text release];
_text = [text retain];
[self setNeedsDisplay];
}
-(void) setTextColor:(UIColor *)textColor {
[_textColor release];
_textColor = [textColor retain];
[self setNeedsDisplay];
}
-(void) setFont:(NSString *)font {
[_font release];
_font = [font retain];
[self setNeedsDisplay];
}
-(void) setFontSize:(float)fontSize {
_fontSize = fontSize;
[self setNeedsDisplay];
}
-(void) setStrokeColor:(UIColor *)strokeColor {
[_strokeColor release];
_strokeColor = strokeColor;
[self setNeedsDisplay];
}
-(void) setStrokeWidth:(float)strokeWidth {
_strokeWidth = 0 ? (strokeWidth < 0) : (-1 * strokeWidth);
[self setNeedsDisplay];
}
-(void) setTextAlignment:(CTTextAlignment)textAlignment {
_textAlignment = textAlignment;
[self setNeedsDisplay];
}
-(void) setFrame:(CGRect)frame {
[super setFrame: frame];
[self setNeedsDisplay];
}
-(float) suggestedHeightForWidth:(float) width {
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)_font, _fontSize, NULL);
CTParagraphStyleSetting paragraphStyles[2] = {
{.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void *) &_lineBreakMode},
{.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void *) &_textAlignment}
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphStyles, 2);
NSDictionary *attrDict = [[NSDictionary alloc] initWithObjectsAndKeys:(id)fontRef, (NSString *)kCTFontAttributeName, (id)_textColor.CGColor, (NSString *)(kCTForegroundColorAttributeName), (id)_strokeColor.CGColor, (NSString *)(kCTStrokeColorAttributeName), (id)[NSNumber numberWithFloat: _strokeWidth], (NSString *)(kCTStrokeWidthAttributeName), (id)paragraphStyle, (NSString *)(kCTParagraphStyleAttributeName), nil];
CFRelease(fontRef);
CFRelease(paragraphStyle);
NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:_text attributes: attrDict];
// Determine suggested frame height
CFRange textRange = CFRangeMake(0, [attrStr length]);
CGSize constraint = CGSizeMake(width, 9999);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrStr);
CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, constraint, NULL);
textSize = CGSizeMake(ceilf(textSize.width), ceilf(textSize.height));
[attrDict release];
[attrStr release];
return textSize.height;
}
-(void) renderText:(CGContextRef)ctx {
CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);
CGContextTranslateCTM(ctx, 0, self.bounds.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)_font, _fontSize, NULL);
CTParagraphStyleSetting paragraphStyles[2] = {
{.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void *) &_lineBreakMode},
{.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void *) &_textAlignment}
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphStyles, 2);
NSDictionary *attrDict = [[NSDictionary alloc] initWithObjectsAndKeys:(id)fontRef, (NSString *)kCTFontAttributeName, (id)_textColor.CGColor, (NSString *)(kCTForegroundColorAttributeName), (id)_strokeColor.CGColor, (NSString *)(kCTStrokeColorAttributeName), (id)[NSNumber numberWithFloat: _strokeWidth], (NSString *)(kCTStrokeWidthAttributeName), (id)paragraphStyle, (NSString *)(kCTParagraphStyleAttributeName), nil];
CFRelease(fontRef);
CFRelease(paragraphStyle);
NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:_text attributes: attrDict];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, self.bounds);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrStr);
CFRange textRange = CFRangeMake(0, [attrStr length]);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, textRange, path, NULL);
CFArrayRef lines = CTFrameGetLines(frame);
NSInteger numberOfLines = CFArrayGetCount(lines);
CGPoint lineOrigins[numberOfLines];
CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins);
for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) {
CGPoint lineOrigin = lineOrigins[lineIndex];
CGContextSetTextPosition(ctx, lineOrigin.x, lineOrigin.y);
CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex);
if (lineIndex == numberOfLines - 1) {
CFRange lastLineRange = CTLineGetStringRange(line);
if (!(lastLineRange.length == 0 && lastLineRange.location == 0) && lastLineRange.location + lastLineRange.length < textRange.location + textRange.length) {
NSUInteger truncationAttributePosition = lastLineRange.location;
CTLineTruncationType truncationType;
if (numberOfLines != 1) {
truncationType = kCTLineTruncationEnd;
truncationAttributePosition += (lastLineRange.length - 1);
}
NSAttributedString *tokenString = [[NSAttributedString alloc] initWithString:@"\u2026" attributes:attrDict];
CTLineRef truncationToken = CTLineCreateWithAttributedString((CFAttributedStringRef)tokenString);
NSMutableAttributedString *truncationString = [[attrStr attributedSubstringFromRange: NSMakeRange(lastLineRange.location, lastLineRange.length)] mutableCopy];
if (lastLineRange.length > 0) {
unichar lastCharacter = [[truncationString string] characterAtIndex: lastLineRange.length - 1];
if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastCharacter]) {
[truncationString deleteCharactersInRange:NSMakeRange(lastLineRange.length - 1, 1)];
}
}
[truncationString appendAttributedString: tokenString];
CTLineRef truncationLine = CTLineCreateWithAttributedString((CFAttributedStringRef) truncationString);
CTLineRef truncatedLine = CTLineCreateTruncatedLine(truncationLine, self.bounds.size.width, truncationType, truncationToken);
if (!truncatedLine) {
// If the line is not as wide as the truncationToken, truncatedLine is NULL
truncatedLine = CFRetain(truncationToken);
}
CTLineDraw(truncatedLine, ctx);
CFRelease(truncatedLine);
CFRelease(truncationLine);
CFRelease(truncationToken);
} else {
CTLineDraw(line, ctx);
}
} else {
CTLineDraw(line, ctx);
}
}
[attrStr release];
[attrDict release];
CFRelease(path);
CFRelease(frame);
CFRelease(framesetter);
}
-(void) drawInContext:(CGContextRef)ctx {
[super drawInContext: ctx];
[self renderText: ctx];
}
@end
我认为,以支持您可以创建文本层的类别,类别可以为这两个版本的代码有条件它。 同我们为导航栏做当我们改变形象。
当你与不同的IOS版本不同的帧你可以居中你的框架
这在我看来,iOS 6中已考虑到行高(或其他字体相关的功能影响字形的实际垂直绘制位置)绘制CATextLayer的文本内容时的字体。 其结果是,在IOS 6.0,在CATextLayer与某种字体的文本没有在CATextLayer的框架的顶部边缘显示。 我发现,有些字体有这样的垂直填充,而有的则没有。 而在IOS 5.0 / 5.1,该文本的字形实际上在CATextLayer的框架的顶部边缘显示。
所以,一个可能的解决方案我想可能是改变textLayer对象在你的代码CATextLayer只是CALayer的(或子类的CALayer),并使用核心文本自定义得出这样的内容,你能控制一切,将跨越一致的iOS 5.0 / 5.1和6.0。