CATextLayer上iOS 6不需要的垂直填充
背景:我在iOS 5中启动了我的项目,并用图层构建了一个漂亮的按钮。我在按钮上添加了一个textLayer,并使用以下代码将其居中:CATextLayer上iOS 6不需要的垂直填充,ios,ipad,ios6,layer,catextlayer,Ios,Ipad,Ios6,Layer,Catextlayer,背景:我在iOS 5中启动了我的项目,并用图层构建了一个漂亮的按钮。我在按钮上添加了一个textLayer,并使用以下代码将其居中: float textLayerVerticlePadding = ((self.bounds.size.height - fontSize) /2); textLayer = [[CATextLayer alloc]init]; [textLayer setFrame:CGRectOffset(self.bounds, 0, textLay
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不会这样做?因为我想同时支持iOS5和iOS6(对于那些喜欢谷歌地图的人)
图片:这是iOS5,红色是textLayer的背景(为了让它更明显) 这是iOS 6
更新:虽然我确信下面所有的答案都是正确的,但我发现这篇文章是通过第一个最简单的方法来实现的
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)];
有了这个密码,我每次都有一个死点。请注意,这仅在iOS5和iOS6上使用HelveticaNeue Bold进行测试。我不能再说别的了。我认为要支持这两个版本,您可以为文本层创建一个类别,在类别中,您可以有条件地为两个版本编写代码。 和我们在更改图像时对导航栏所做的相同
您可以像对待不同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中一致的所有内容。我在等待最终解决方案,我学习了RTLabel和TTtatAttributedLabel,并按照Steve的建议制作了一个简单的类在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:CALayer{
NSString*\u文本;
UIColor*_textColor;
NSString*\u字体;
浮动大小;
UIColor*_strokeColor;
浮动_冲程宽度;
CTTextAlignment _textAlignment;
int_lineBreakMode;
浮动高度;
}
-(浮动)宽度的建议高度:(浮动)宽度;
@属性(非原子,保留)NSString*文本;
@属性(非原子,保留)UIColor*textColor;
@属性(非原子,保留)NSString*字体;
@属性(非原子,赋值)浮点fontSize;
@属性(非原子,保留)UIColor*strokeColor;
@属性(非原子,赋值)float strokeWidth;
@属性(非原子,赋值)CTTextAlignment;
@结束
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
#导入
#导入“CustomTextLayer.h”
@CustomTextLayer的实现
@合成文本=_text,textColor=_textColor;
@合成字体=_字体,字体大小=_字体大小;
@合成strokeColor=\u strokeColor,strokeWidth=\u strokeWidth;
@合成textAlignment=\u textAlignment;
-(id)init{
if(self=[super init]){
_文本=@;
_textColor=[UIColor blackColor];
_font=@“Helvetica”;
_fontSize=12;
_strokeColor=[UIColor whiteColor];
_冲程宽度=0.0;
_textAlignment=kCTLeftTextAlignment;
_lineBreakMode=kCTLineBreakByWordWrapping;
}
回归自我;
}
-(无效)解除锁定{
[文本发布];
[_textcolorrelease];
[_字体发布];
[_StrokeColorRelease];
[super dealoc];
}
-(void)setText:(NSString*)文本{
[文本发布];
_text=[文本保留];
[自我设置需要显示];
}
-(void)setTextColor:(UIColor*)textColor{
[_textcolorrelease];
_textColor=[textColor retain];
[自我设置需要显示];
}
-(void)setFont:(NSString*)字体{
[_字体发布];
_font=[font retain];
[自我设置需要显示];
}
-(无效)setFontSize:(浮动)fontSize{
_fontSize=fontSize;
[自我设置需要显示];
}
-(无效)设置行程颜色:(UIColor*)行程颜色{
[_StrokeColorRelease];
_strokeColor=strokeColor;
[自我设置需要显示];
}
-(无效)设置行程宽度:(浮动)行程宽度{
_冲程宽度=0?(冲程宽度<0):(-1*冲程宽度);
[自我设置需要显示];
}
-(void)setTextAlignment:(CTTextAlignment)textAlignment{
_textAlignment=textAlignment;
[自我设置需要显示];
}
-(void)setFrame:(CGRect)frame{
[超级设置帧:帧];
[自我设置需要显示];
}
-(浮动)宽度的建议高度:(浮动)宽度{
CTFontRef fontRef=CTFontCreateWithName((CFStringRef)_font,_fontSize,NULL);
CTParagraphStyleSetting段落样式[2]={
{.spec=kCTParagraphStyleSpecifierLineBreakMode,.valueSize=sizeof(CTLineBreakMode),.value=(const void*)和_lineBreakMode},
{.spec=kCTParagraphStyleSpecifierAlignment,.valueSize=sizeof(CTTextAlignment),.value=(const void*)和_textAlignment}
};
CTPara
- (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;
}
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);