来自iOS 6的CATextLayer上的不需要的垂直填充 [英] Unwanted Vertical Padding from iOS 6 on CATextLayer

查看:127
本文介绍了来自iOS 6的CATextLayer上的不需要的垂直填充的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

后台:我在iOS 5中启动了我的项目,并构建了一个带图层的漂亮按钮。我在按钮上添加了一个textLayer并使用以下代码将其居中:

Background: I started my project in iOS 5 and built out a beautiful button with layer. I added a textLayer onto the button and center it using the following code:

    float textLayerVerticlePadding = ((self.bounds.size.height - fontSize) /2);
    textLayer = [[CATextLayer alloc]init];
    [textLayer setFrame:CGRectOffset(self.bounds, 0, textLayerVerticlePadding)];

它工作得很好,在iOS 6之前看起来很中心。

It works great and looks dead center until iOS 6.

问题: iOS 6在textLayer中最顶层边界和文本之间添加了空格(填充)。这扰乱了上面的计算。有没有办法确保iOS 6没有?因为我想支持iOS 5和6(对于那些喜欢谷歌地图的人)。

Problem: iOS 6 added a space (padding) between the topmost bound and the text in textLayer. This upsets the calculation above. Is there a way to make sure that iOS 6 does not? because I would like to support both iOS 5 and 6 (for those who prefers Google Map).

图片:


这个是iOS 5,红色是textLayer的背景(为了实现它)更明显)

Pictures:
This one is iOS 5 and the red color is the background of the textLayer (to make it more apparent)

这个是iOS 6

And this one is iOS 6

更新:虽然我确定以下所有答案都是正确的,但我发现t0rst的帖子最简单的执行方式。 HelveticaNeue 为iOS5和iOS6留出一点空间,与 Helvetica 不同,它在iOS5顶部没有任何空间iOS6中的空间。

Update: While im sure all the answers below are correct in their own ways, I found the post by t0rst simplest way to execute this. HelveticaNeue leaves a little space for both iOS5 and iOS6, unlike Helvetica which leaves no space on the top in iOS5 and little space in iOS6.

更新2:再玩一遍,找出小空间的大小。没有详细说明,空间是字体大小的1/6。所以为了弥补它,我写了

Update 2: Played around with it a little more, and found out the size of the little space. Without going into detail, the space is 1/6 of your font size. So to compensate for it I wrote

float textLayerVerticlePadding = ((self.bounds.size.height - fontSize) /2) - (fontSize/6);
[textLayer setFrame:CGRectOffset(self.bounds, 0, textLayerVerticlePadding)];

有了这段代码,我每次都会得到一个死角。请注意,这仅在iOS5和iOS6上使用 HelveticaNeue-Bold 进行测试。我不能说其他任何事情。

With that code, I get a dead center every time. Note that this is only tested with HelveticaNeue-Bold on iOS5 and iOS6. I cannot say for anything else.

推荐答案

在iOS 5及之前, CATextLayer中的第一个基线当传递 CTLine 总是从 CTLineGetTypographicBounds 获得的上升位置从顶部向下定位$ c>使用第一行的字符串。

In iOS 5 and before, the first baseline in a CATextLayer is always positioned down from the top of the bounds by the ascent obtained from CTLineGetTypographicBounds when passed a CTLine made with the string for the first line.

在iOS 6中,这不再适用于所有字体。因此,当您定位 CATextLayer 时,您无法再可靠地决定将其放置在何处以获得正确的视觉对齐。或者你呢? ...

In iOS 6, this doesn't hold true for all fonts anymore. Hence, when you are positioning a CATextLayer you can no longer reliably decide where to put it to get the right visual alignment. Or can you? ...

首先,暂时搁置:当我试图解决 CATextLayer 之前的定位行为时iOS 5,我尝试使用帽子高度的所有组合,来自UIFont的Ascender等,最后发现从 CTLineGetTypographicBounds 的上升是我需要的。在这个过程中,我发现a)从 UIFont ascender上升 CTFontGetAscent CTLineGetTypographicBounds 对于某些字体是不一致的,并且b)上升经常是奇怪的 - 要么裁剪重音,要么离开上面的空间。 a)的解决方案是知道要使用哪个值。 b)除了通过抵消 CATextLayer 边界而留下足够的空间以外,如果它可能会有被剪裁的重音符号,则没有真正的解决方案。

First, an aside: when trying to work out CATextLayer's positioning behaviour a while ago in iOS 5, I tried using all combinations of cap height, ascender from UIFont, etc. before finally discovering that ascent from CTLineGetTypographicBounds was the one I needed. In the process, I discovered that a) the ascent from UIFont ascender, CTFontGetAscent and CTLineGetTypographicBounds are inconsistent for certain typefaces, and b) the ascent is frequently strange - either cropping the accents or leaving way to much space above. The solution to a) is to know which value to use. There isn't really a solution to b) other than to leave plenty of room above by offsetting CATextLayer bounds if it likely you will have accents that get clipped.

返回iOS 6.如果你避免使用最严重的违规字体(从6.0开始,可能会有变化),你仍然可以进行 CATextLayer <的编程定位/ code>与其他字体一起使用。违规者是: AcademyEngravedLetPlain Courier HoeflerText Palatino - 从视觉上看,这些家庭的位置正确(即没有剪裁) )在 CATextLayer 中,但三个上升源中没有一个为您提供基线放置位置的可用指示。 Helvetica .HelveticaNeueUI (又称系统字体)系列在 UIFont ascender 给出的上升时正确定位基线,但是其他上升来源没有用。

Back to iOS 6. If you avoid the worst offending typefaces (as of 6.0, and probably subject to change), you can still do programatic positioning of CATextLayer with the rest of the typefaces. The offenders are: AcademyEngravedLetPlain, Courier, HoeflerText and Palatino - visually, these families position correctly (i.e. without clipping) in CATextLayer, but none of the three ascent sources gives you a usable indication of where the baseline is placed. Helvetica and .HelveticaNeueUI (aka system font) families position correctly with baseline at the ascent given by UIFont ascender, but the other ascent sources are not of use.

我做的测试的一些例子。示例文本以不同颜色绘制三次。坐标原点位于灰色框的左上角。黑色文字由 CTLineDraw CTLineGetTypographicBounds 的上升向下偏移;透明红色由 CATextLayer 绘制,边界等于灰色框;透明蓝色用 UIKit NSString 添加 drawAtPoint:withFont:找到灰色框的原点并使用 UIFont

Some examples from tests I did. The sample text is drawn three times in different colours. The coordinate origin is top left of grey box. Black text is drawn by CTLineDraw offset downwards by the ascent from CTLineGetTypographicBounds; transparent red is drawn by CATextLayer with bounds equal to the grey box; transparent blue is drawn with the UIKit NSString addition drawAtPoint:withFont: locating at the origin of the grey box and with the UIFont.

1)表现良好的字体,铜版,光。三个样本是重合的,给出了栗色,并且意味着所有来源的上升距离足够近。适用于iOS 5和6。

1) A well behaved font, Copperplate-Light. The three samples are coincident, giving maroon, and meaning that the ascents are near enough the same from all sources. Same for iOS 5 and 6.

2) Courier CATextLayer 文字位置太高(红色),但 CTLineDraw CTLineGetTypographicBounds (黑色)匹配 CATextLayer 定位 - 所以我们可以从那里放置并纠正。 NSString drawAtPoint:withFont:(蓝色)放置文本而不剪裁。 ( Helvetica .HelveticaNeueUI 在iOS 6中的行为如此)

2) Courier under iOS 5. CATextLayer positions text too high (red), but CTLineDraw with ascent from CTLineGetTypographicBounds (black) matches CATextLayer positioning - so we can place and correct from there. NSString drawAtPoint:withFont: (blue) places the text without clipping. (Helvetica and .HelveticaNeueUI behave like this in iOS 6)

3) Courier code> CATextLayer (红色)现在放置文本以使其不被剪裁,但定位不再与 CTLineGetTypographicBounds 的上升匹配(黑色)或来自 UIFont ascender在 NSString drawAtPoint:withFont:(蓝色)中使用。这对于编程定位是不可用的。 ( AcademyEngravedLetPlain HoeflerText Palatino 在iOS 6中也表现如此)

3) Courier under iOS 6. CATextLayer (red) now places the text so that it is not clipped, but the positioning no longer matches the ascent from CTLineGetTypographicBounds (black) or from UIFont ascender used in NSString drawAtPoint:withFont: (blue). This is unusable for programatic positioning. (AcademyEngravedLetPlain, HoeflerText and Palatino also behave like this in iOS 6)

希望这有助于避免某些我经历了浪费的时间,如果你想深入一点,可以玩一下:

Hope this helps avoid some of the hours of wasted time I went through, and if you want to dip in a bit deeper, have a play with this:

- (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;
}

这篇关于来自iOS 6的CATextLayer上的不需要的垂直填充的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆