如何检查UILabel是否被截断?

Ran*_*all 97 iphone truncate objective-c uilabel ios

我有一个UILabel依赖于我的应用程序是否被纵向或横向模式下运行在iPhone或iPad,可以长短不一.当文本太长而无法在一行显示并且它被截断时,我希望用户能够按下它并获得全文的弹出窗口.

如何查看是否UILabel截断文本?它甚至可能吗?现在我只是根据我所处的模式检查不同长度,但它不能很好地工作.

pro*_*rmr 102

您可以计算字符串宽度,并查看宽度是否大于label.bounds.size.width

NSString UIKit Additions有几种方法可以用特定字体计算字符串的大小.但是,如果您的标签有minimumFontSize,则允许系统将文本缩小到该大小.您可能想要使用sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:在这种情况下.

CGSize size = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}];
if (size.width > label.bounds.size.width) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

  • 不推荐使用sizeWithFont:[label.text sizeWithAttributes:@ {NSFontAttributeName:label.font}]; (16认同)
  • 什么时候`numberOfLines> 0`? (12认同)
  • 它只有在label.numberofline == 0时才有效,不是吗? (5认同)
  • @fatuhoku`numberOfLines`返回用于显示文本的最大行数,如UILabel类参考中所述:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UILabel_Class/index。 html#// apple_ref / occ / instp / UILabel / numberOfLines (2认同)

小智 78

Swift(作为扩展) - 适用于多行uilabel:

swift4 :( 略有变化的attributesparam boundingRect)

extension UILabel {

    var isTruncated: Bool {

        guard let labelText = text else {
            return false
        }

        let labelTextSize = (labelText as NSString).boundingRect(
            with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
            options: .usesLineFragmentOrigin,
            attributes: [.font: font],
            context: nil).size

        return labelTextSize.height > bounds.size.height
    }
}
Run Code Online (Sandbox Code Playgroud)

swift3:

extension UILabel {

    var isTruncated: Bool {

        guard let labelText = text else { 
            return false
        }

        let labelTextSize = (labelText as NSString).boundingRect(
            with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
            options: .usesLineFragmentOrigin,
            attributes: [NSFontAttributeName: font],
            context: nil).size

        return labelTextSize.height > bounds.size.height
    }
}
Run Code Online (Sandbox Code Playgroud)

swift2:

extension UILabel {

    func isTruncated() -> Bool {

        if let string = self.text {

            let size: CGSize = (string as NSString).boundingRectWithSize(
                CGSize(width: self.frame.size.width, height: CGFloat(FLT_MAX)),
                options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                attributes: [NSFontAttributeName: self.font],
                context: nil).size

            if (size.height > self.bounds.size.height) {
                return true
            }
        }

        return false
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 对于swift 3,我会使用CGFloat.greatestFiniteMagnitude (2认同)
  • 很好的答案,但最好使用计算属性而不是func:var isTruncated:Bool {if let string = self.text {let size:CGSize =(string as NSString).boundingRect(with:CGSize(width:self.frame.size) .width,height:CGFloat.greatestFiniteMagnitude),options:NSStringDrawingOptions.usesLineFragmentOrigin,attributes:[NSFontAttributeName:self.font],context:nil).size return(size.height> self.bounds.size.height)} return false} (2认同)

Mar*_*tin 19

编辑:我刚刚看到我的回答被upvoted,但我给出的代码片段已被弃用.
现在最好的方法是(ARC):

NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = mylabel.lineBreakMode;
NSDictionary *attributes = @{NSFontAttributeName : mylabel.font,
                             NSParagraphStyleAttributeName : paragraph};
CGSize constrainedSize = CGSizeMake(mylabel.bounds.size.width, NSIntegerMax);
CGRect rect = [mylabel.text boundingRectWithSize:constrainedSize
                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                      attributes:attributes context:nil];
if (rect.size.height > mylabel.bounds.size.height) {
    NSLog(@"TOO MUCH");
}
Run Code Online (Sandbox Code Playgroud)

请注意,计算的大小不是整数值.因此,如果你这样做int height = rect.size.height,你将失去一些浮点精度,可能会有错误的结果.

旧答案(不建议使用):

如果您的标签是多行的,则可以使用以下代码:

CGSize perfectSize = [mylabel.text sizeWithFont:mylabel.font constrainedToSize:CGSizeMake(mylabel.bounds.size.width, NSIntegerMax) lineBreakMode:mylabel.lineBreakMode];
if (perfectSize.height > mylabel.bounds.size.height) {
    NSLog(@"TOO MUCH");
}
Run Code Online (Sandbox Code Playgroud)


Adr*_*ian 19

似乎intrinsicContentSize可以完成带有attributedText和设置文本的标签的工作text。考虑到这一点,我认为我们可以安全地放弃所有边界框簿记并简化如下:

斯威夫特 5.x

extension UILabel {
    var isTruncated: Bool {
       frame.width < intrinsicContentSize.width
    }

    var isClipped: Bool {
        frame.height < intrinsicContentSize.height
    }
}
Run Code Online (Sandbox Code Playgroud)


Don*_*gXu 13

你可以用UILabel制作一个类别

- (BOOL)isTextTruncated

{
    CGRect testBounds = self.bounds;
    testBounds.size.height = NSIntegerMax;
    CGRect limitActual = [self textRectForBounds:[self bounds] limitedToNumberOfLines:self.numberOfLines];
    CGRect limitTest = [self textRectForBounds:testBounds limitedToNumberOfLines:self.numberOfLines + 1];
    return limitTest.size.height>limitActual.size.height;
}
Run Code Online (Sandbox Code Playgroud)

  • 来自doc:`textRectForBounds:limitedToNumberOfLines:`"你不应该直接调用这个方法"...... (3认同)

Raj*_*esh 9

使用此类别查找是否在iOS 7及更高版本上截断标签.

// UILabel+Truncation.h
@interface UILabel (Truncation)

@property (nonatomic, readonly) BOOL isTruncated;

@end


// UILabel+Truncation.m
@implementation UILabel (Truncation)

- (BOOL)isTruncated
{
    CGSize sizeOfText =
      [self.text boundingRectWithSize:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)
                               options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                            attributes:@{ NSFontAttributeName : label.font } 
                               context: nil].size;

    if (self.frame.size.height < ceilf(sizeOfText.height))
    {
        return YES;
    }
    return NO;
}

@end
Run Code Online (Sandbox Code Playgroud)


onm*_*133 8

要添加到iDev的答案,您应该使用intrinsicContentSize而不是frame,使其适用于Autolayout

- (BOOL)isTruncated:(UILabel *)label{
        CGSize sizeOfText = [label.text boundingRectWithSize: CGSizeMake(label.intrinsicContentSize.width, CGFLOAT_MAX)
                                                     options: (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                  attributes: [NSDictionary dictionaryWithObject:label.font forKey:NSFontAttributeName] context: nil].size;

        if (self.intrinsicContentSize.height < ceilf(sizeOfText.height)) {
        return YES;
    }
    return NO;
}
Run Code Online (Sandbox Code Playgroud)


Cla*_*aus 8

斯威夫特3

您可以在分配字符串后计算行数,并与标签的最大行数进行比较.

import Foundation
import UIKit

extension UILabel {

    func countLabelLines() -> Int {
        // Call self.layoutIfNeeded() if your view is uses auto layout
        let myText = self.text! as NSString
        let attributes = [NSFontAttributeName : self.font]

        let labelSize = myText.boundingRect(with: CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil)
        return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight))
    }

    func isTruncated() -> Bool {

        if (self.countLabelLines() > self.numberOfLines) {
            return true
        }
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)


Luc*_*hwe 5

就是这个。这与配合使用attributedText,然后又回到朴素text,这对于处理多个字体系列,大小甚至NSTextAttachments的我们来说非常有意义。

使用autolayout可以很好地工作,但是显然在检查之前必须定义和设置约束isTruncated,否则标签本身甚至不知道如何进行布局,因此甚至也无法知道其是否被截断。

它不工作,只是一个普通的来处理这个问题NSStringsizeThatFits。我不确定人们是如何取得积极成果的。正如无数次提到的那样,BTW sizeThatFits根本不是理想的选择,因为它考虑到numberOfLines了生成的大小,这违背了我们试图做的全部目的,因为无论其是否被截断,它isTruncated总是会返回false

extension UILabel {
    var isTruncated: Bool {
        layoutIfNeeded()

        let rectBounds = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
        var fullTextHeight: CGFloat?

        if attributedText != nil {
            fullTextHeight = attributedText?.boundingRect(with: rectBounds, options: .usesLineFragmentOrigin, context: nil).size.height
        } else {
            fullTextHeight = text?.boundingRect(with: rectBounds, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil).size.height
        }

        return (fullTextHeight ?? 0) > bounds.size.height
    }
}
Run Code Online (Sandbox Code Playgroud)