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

标签 cocoa-touch uilabel

我有一个布局,其中 UILabel 放置在固定宽度的 View 上方,如下图所示为灰色矩形。

Text scales well without kerning

文本需要匹配固定灰色 View 的宽度。

我通过将 UILabel 上的 adjustsFontSizeToFitWidth 属性设置为 YES,将字体大小设置为非常大,并将minimumScaleFactor 为合适的小值。 在……之前一切正常

我不得不为所述文本添加字距调整。我通过将 @{NSKernAttributeName: @1.40} 应用于属性字符串来添加字距调整,然后传递属性字符串 UILabelattributedText 属性。不幸的是,这似乎阻碍了自动缩放,因为这会导致文本被正确调整,但字符串的末尾被截断。就好像标签在不考虑字距调整的情况下缩小了文本。

Text truncated when kerning is added

如何让给定的字符串使用字距调整以我选择的宽度(即灰色 View 的宽度)呈现?

最佳答案

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

此扩展使用 quicksort pivot 的想法来快速找到使字符串适合所需宽度的字距调整。

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

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

希望你喜欢。

@implementation NSString(扩展)

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

关于cocoa-touch - 使用字距调整动态调整文本大小以占据 UILabel 的整个宽度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25360991/

相关文章:

ios - 如何使用核心文本在ios中的不同UIlabel文本行上设置不同的字体样式

objective-c - 更新 "while loop"中的 UILabel

objective-c - UITableViewRowAnimation 自定义动画

iphone - 旋转时如何将按钮锚定到 View 底部?

objective-c - 枚举 NSMutableDictionary - 无法从循环内访问对象属性

ios - UILabel 下划线文本,高字符低于基线

ios - 调整 UITextfield 宽度

iphone - UIGestureRecognizer 阻止 UITableView 在 Xcode 4.5 中滚动

iphone - 以编程方式从 UILabel 创建图像

ios - 将 UILabel 设置为隐藏