首页 文章

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

提问于
浏览
15

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

enter image description here

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

enter image description here

existing solution涉及调用sizeToFit或更新uilabel的框架以匹配文本的高度 . 不幸的是,后者(虽然丑陋)解决方案并不应该更新帧 . 前一种解决方案基本上不能使用有限数量的行和自动收缩 .

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

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

4 回答

  • -3

    这个问题是真正的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
    

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

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

  • 2

    所以我找到了一个解决方法 . 这有点冒险,但它确实有效 .

    所以我所做的是在IB中为我的文本行添加一个高度约束,并在我的视图中获取对该文本的引用 .

    然后在layoutSubviews中,我根据字体的大小更新我的约束高度,我必须计算:

    - (void)layoutSubviews {
        if (self.titleLabel.text) {
            CGFloat actualFontSize;
            CGSize titleSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font minFontSize:9.0 actualFontSize:&actualFontSize forWidth:self.titleLabel.frame.size.width lineBreakMode:NSLineBreakByTruncatingTail];
            CGRect lineBox = CTFontGetBoundingBox((__bridge CTFontRef)([UIFont fontWithName:@"ProximaNova-Regular" size:actualFontSize]));
            self.titleHeightConstraint.constant = lineBox.size.height;
        }
        [super layoutSubviews];
    }
    

    起初我只是将它设置为实际的字体大小,但即使调整(* 1.2)它仍然剪裁较小的字体大小 . 关键是使用 CTFontGetBoundingBox ,字体大小由我的计算确定 .

    这非常不幸,我希望有更好的方法 . 也许我应该转向包装 .

  • 7

    TomSwift感谢您的回答,我真的很难解决这个问题 .

    如果某人仍然有奇怪的行为,我不得不改变:

    intrinsicContentSize = CGSizeMake(inaccurateSize.width,accurateHeight);

    intrinsicContentSize = CGSizeMake(inaccurateSize.width,accurateHeight * 2);

    然后它像魅力一样工作 .

  • 1

    您正在寻找的是这两行代码 .

    myLabel.numberOfLines = 0;
    myLabel.lineBreakMode = UILineBreakModeWordWrap;
    

    您还可以在“换行符”和“行”下的属性检查器中找到它 .

相关问题