本文介绍了垂直对齐UILabel文本与约束,没有换行(自动布局,单行)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So I have my view setup in IB such that this text label aligns with the top of the thumbnail via constraints.

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

However as we know, you can't vertically align text in a UILabel. My text updates the font size based on the length of the content. Full size text looks great, while small text is significantly lower on the view.

涉及调用sizeToFit或更新uilabel的框架以匹配文字的高度。不幸的是,后者(虽然很难看)解决方案不能很好地解决你不应该更新框架的限制。当你需要让文本自动收缩直到它被截断时,前一个解决方案基本上不起作用。 (所以它不适用于有限数量的行和自动收缩)。

The existing solution involves either calling sizeToFit or updating the frame of the uilabel to match the height of the text. Unfortunately the latter (albeit ugly) solution doesn't play well with constraints where you aren't supposed to update the frame. The former solution basically doesn't work when you need to have the text autoshrink until it truncates. (So it doesn't work with a restricted number of lines and autoshrink).

现在为什么uilabel的内在大小(高度)不会更新像通过尺寸适合内容将宽度设置为自然尺寸超出我的范围。似乎应该是这样,但事实并非如此。

Now as to why the intrinsic size (height) of the uilabel doesn't update like the width does when it's set to it's natural size via "Size to fit content" is beyond me. Seems like it definitely should, but it doesn't.

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

So I'm left looking for alternative solutions. As far as I can see, you might have to set a height constraint on the label, and adjust the height constant after calculating the height of the text. Anyone have a good solution?

推荐答案

这个问题是一个真正的PITA要解决的问题。在iOS7中不推荐使用API​​,或者iOS7替换API已被破坏,这无济于事。 Blah!

This problem is a real PITA to solve. It doesn't help that the API's that work are deprecated in iOS7, or that the iOS7 replacement API's are broken. Blah!

你的解决方案很好,但它使用了一个弃用的API( sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:),它的封装效果不是很好 - 您需要将此代码复制到您想要此行为的任何单元格或视图。从好的方面来说,这是相当有效的!一个错误可能是当你进行计算时标签还没有布局,但你根据它的宽度进行计算。

Your solution is nice, however it uses a deprecated API (sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:), and it's not very well encapsulated - you need to copy this code around to any cells or views where you want this behavior. On the plus side it's fairly efficient! One bug may be that the label hasn't been laid out yet when you do your calculation, but you perform your calculation based on its width.

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

I propose that you encapsulate this behavior in a UILabel subclass. By placing the sizing calculation in an overridden intrinsicContentSize method the label will auto-size itself. I wrote the following, which incorporates your code that will execute on iOS6, and my version using non-deprecated API's for iOS7 or better:

@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

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

This implementation isn't perfect. I had to ensure using baselineAdjustment == UIBaselineAdjustmentAlignCenters, and I'm not 100% certain I understand why. And I'm not happy with the hoops I had to jump through to get an accurate text height. There's also a few pixel difference between what my calculation produces, and yours. Feel free to play with it and adjust as necessary :)

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

The boundingRectWithSize:options:attributes:context API seems pretty broken to me. While it (mostly!) correctly constrains the text to the input size, it doesn't calculate the correct height! The height it returns is based on the line-height of the supplied font, even if a scaling is in play. My guess is this is why UILabel doesn't have this behavior by default? My workaround is to calculate an unconstrained size where both the height and width are accurate, then use the ratio between the constrained and unconstrained widths to calculate the accurate height for the constrained size. What a PITA. There are lots of complaints in the Apple dev forums and here on SO that point out that this API has a number of issues like this.

这篇关于垂直对齐UILabel文本与约束,没有换行(自动布局,单行)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-31 02:45