垂直对齐UILabel文本与约束,没有换行(自动布局,单行)

Bob*_*ryn 15 ios autolayout

因此,我在IB中设置了视图,使得此文本标签通过约束与缩略图的顶部对齐.

在此输入图像描述

但是,正如我们所知,您无法在UILabel中垂直对齐文本.我的文本根据内容的长度更新字体大小.全尺寸文本看起来很棒,而视图上的小文本明显较低.

在此输入图像描述

现有的解决方案涉及任一呼叫sizeToFit或更新的UILabel的帧匹配的文本的高度.不幸的是,后者(尽管很难看)解决方案不能很好地解决你不应该更新框架的限制.当你需要让文本自动收缩直到它被截断时,前一个解决方案基本上不起作用.(因此它不适用于有限数量的行和自动收缩).

现在,为什么uilabel的内在尺寸(高度)不像宽度那样更新,当它被设置为它的自然尺寸时,通过"尺寸适合内容"超出了我.似乎它肯定应该,但事实并非如此.

所以我一直在寻找其他解决方案.据我所见,您可能需要在标签上设置高度约束,并在计算文本高度后调整高度常量.谁有一个很好的解决方案?

Tom*_*ift 7

这个问题是真正的PITA要解决的问题.在iOS7中不推荐使用API​​,或者iOS7替换API被破坏了.胡说!

你的解决方案很不错,但是它使用了一个不推荐使用的API(sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:),并且封装得不是很好 - 你需要将这些代码复制到你想要这种行为的任何单元格或视图.从好的方面来说,这是相当有效的!一个错误可能是您在进行计算时尚未布置标签,但您根据其宽度执行计算.

我建议您将此行为封装在UILabel子类中.通过将大小计算放在重写intrinsicContentSize方法中,标签将自动调整大小.我编写了以下内容,其中包含将在iOS6上执行的代码,以及使用针对iOS7或更高版本的非弃用API的我的版本:

@implementation TSAutoHeightLabel

- (CGSize) intrinsicContentSize
{
    NSAssert( self.baselineAdjustment == UIBaselineAdjustmentAlignCenters, @"Please ensure you are using UIBaselineAdjustmentAlignCenters!" );

    NSAssert( self.numberOfLines == 1, @"This is only for single-line labels!" );

    CGSize intrinsicContentSize;

    if ( [self.text respondsToSelector: @selector( boundingRectWithSize:options:attributes:context: )] )
    {
        NSStringDrawingContext* context = [NSStringDrawingContext new];
        context.minimumScaleFactor = self.minimumScaleFactor;

        CGSize inaccurateSize = [self.text boundingRectWithSize: CGSizeMake( self.bounds.size.width, CGFLOAT_MAX )
                                                        options: NSStringDrawingUsesLineFragmentOrigin
                                                     attributes: @{ NSFontAttributeName : self.font }
                                                        context: context].size;

        CGSize accurateSize = [self.text sizeWithAttributes: @{ NSFontAttributeName : [UIFont fontWithName: self.font.fontName size: 12.0] } ];

        CGFloat accurateHeight = accurateSize.height * inaccurateSize.width / accurateSize.width;

        intrinsicContentSize = CGSizeMake( inaccurateSize.width, accurateHeight);
    }
    else
    {
        CGFloat actualFontSize;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

        [self.text sizeWithFont: self.font
                    minFontSize: self.minimumFontSize
                 actualFontSize: &actualFontSize
                       forWidth: self.frame.size.width
                  lineBreakMode: NSLineBreakByTruncatingTail];

#pragma GCC diagnostic pop

        CGRect lineBox = CTFontGetBoundingBox((__bridge CTFontRef)([UIFont fontWithName: self.font.fontName size: actualFontSize]));

        intrinsicContentSize = lineBox.size;
    }

    return intrinsicContentSize;
}

@end
Run Code Online (Sandbox Code Playgroud)

这种实现并不完美.我必须确保使用baselineAdjustment == UIBaselineAdjustmentAlignCenters,我不是100%确定我理解为什么.而且我不满意我必须跳过的箍以获得准确的文字高度.我的计算和你的计算之间也存在一些像素差异.随意玩它并根据需要调整:)

boundingRectWithSize:options:attributes:contextAPI似乎很破了我.虽然它(大多数!)正确地将文本约束到输入大小,但它不会计算正确的高度!它返回的高度基于所提供字体的行高,即使正在进行缩放.我猜这是为什么UILabel默认情况下没有这种行为?我的解决方法是计算高度和宽度都准确的无约束尺寸,然后使用约束宽度和无约束宽度之间的比率来计算约束尺寸的精确高度.什么是PITA.在Apple开发论坛上有很多抱怨,在这里SO指出这个API有很多这样的问题.