CATextLayer上iOS 6不需要的垂直填充

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

背景:我在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不会这样做?因为我想同时支持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);