使用字距调整动态调整文本大小以占用UILabel的整个宽度

时间:2014-08-18 10:18:46

标签: cocoa-touch uilabel

我有一个布局,UILabel位于固​​定宽度视图上方,如下图所示为灰色矩形。

Text scales well without kerning

文本需要与固定灰色视图的宽度相匹配。

我通过将adjustsFontSizeToFitWidth上的UILabel属性设置为YES来实现此目的,将字体大小设置为非常大的值,并将minimumScaleFactor设置为适合的小值。 此工作正常,直到......

我不得不在文字中添加字距。我通过将@{NSKernAttributeName: @1.40}应用于属性字符串然后传递属性字符串UILabel的{​​{1}}属性来添加字距调整。不幸的是,这似乎残留了自动缩放,因为这会导致文本被正确修改但字符串的末尾被截断。就好像标签将文本缩小而不考虑字距。

Text truncated when kerning is added

如何使用我选择的宽度(即灰色视图的宽度)来渲染具有字距的给定字符串

1 个答案:

答案 0 :(得分:0)

我正在使用下一代码来计算字距(通过创建NSString扩展名)。

此扩展程序正在使用 quicksort 的pivot概念来快速找到使字符串适合所需宽度的字距调整。

请注意,字符串小于-3.0 会使丑陋的字符重叠,因此如果字符串不适合kerning = -3,则算法只返回-3。当然,您可以将 bigKern 变量设置为较小的值。

我针对 UITabBarItem 进行了检查(Apple在标签栏项目标签上使用了字距调整),我的实现非常相似。

希望你喜欢它。

@implementation NSString(Extension)

- (CGFloat)kernForFont:(UIFont *)font toFitWidth:(CGFloat)width
{
    CGSize size = CGSizeMake(CGFLOAT_MAX, font.pointSize*2); // Size to fit.

    const CGFloat threshold = 0.1;
    CGFloat bigKern = -3.0, smallKern = 0.0, pivot = 0.0;
    NSMutableDictionary *attrs = [NSMutableDictionary new];
    attrs[NSFontAttributeName] = font;

    while (true) {
        attrs[NSKernAttributeName] = @(pivot);

        CGRect frame = [self boundingRectWithSize:size
                                          options:NSStringDrawingUsesLineFragmentOrigin
                                       attributes:attrs
                                          context:nil];
        CGFloat diff = width - frame.size.width;
        if (diff > -0.5) {
            // String is fitting.
            if (pivot == 0.0) // Fits without kerning.
                return pivot;
            else if (smallKern - bigKern <= threshold)
                return pivot; // Threshold is reached, return the fitting pivot.
            else {
                // Pivot is fitting, but threshold is not reached, set pivot as max.
                bigKern = pivot;
            }
        }
        else {
            // String not fitting.
            smallKern = pivot;
            if (smallKern - bigKern <= threshold)
                return bigKern;
        }
        pivot = (smallKern + bigKern) / 2.0;
    }

    return bigKern;
}

@end

示例用法,适用于自定义UITabBarItems:

// I have a tabBarItem of type UITabBarItem. textColor is a UIColor.
NSString *title = tabBarItem.title;

CGFloat textLabelWidth = tabBar.frame.size.width / (CGFloat)(self.tabBar.items.count) - 6.0; // 6 is padding.

UIFont *font = [UIFont systemFontOfSize:10.0];
CGFloat kern = [title kernForFont:font toFitWidth:textLabelWidth];

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.alignment = NSTextAlignmentCenter;

NSDictionary *attrs = @{
                        NSFontAttributeName: font,
                        NSKernAttributeName: @(kern),
                        NSForegroundColorAttributeName: textColor,
                        NSParagraphStyleAttributeName: paragraphStyle
                        };
textLabel.attributedText = [[NSAttributedString alloc] initWithString:title attributes:attrs];