Iphone 带有UILineBreakModeWordWrap的UILabel的结果行

Iphone 带有UILineBreakModeWordWrap的UILabel的结果行,iphone,cocoa-touch,iphone-sdk-3.0,nsstring,uilabel,Iphone,Cocoa Touch,Iphone Sdk 3.0,Nsstring,Uilabel,我有一个UILabel,它的大小是用sizeWithFont:方法计算的。换行模式设置为UILineBreakModeWordWrap(使用sizeWithFont:计算大小时使用相同的标志) 一切都很好,标签大小合适,并根据需要显示我的文本 现在我需要知道用于显示标签的行(或者使用sizeWithFont:时生成的行)。从技术上讲,我可以基于空格/插入符号返回来编写自己的断行实现,但这样就不能保证它与苹果的实现方式相同,因此生成的行将不会是用于计算文本大小的行,而不管重新发明轮子的事实如何 理

我有一个UILabel,它的大小是用
sizeWithFont:
方法计算的。换行模式设置为
UILineBreakModeWordWrap
(使用
sizeWithFont:
计算大小时使用相同的标志)

一切都很好,标签大小合适,并根据需要显示我的文本

现在我需要知道用于显示标签的行(或者使用
sizeWithFont:
时生成的行)。从技术上讲,我可以基于空格/插入符号返回来编写自己的断行实现,但这样就不能保证它与苹果的实现方式相同,因此生成的行将不会是用于计算文本大小的行,而不管重新发明轮子的事实如何

理想情况下,我将传递字符串,指定宽度和换行模式,并接收表示文本可视行的字符串数组


有什么办法可以让这一切以最优雅的方式发生吗?

我认为没有什么灵丹妙药可以解决这个问题

这里有一个分类方法,它似乎适用于我抛出的几个基本测试用例。不保证它不会因为复杂的事情而崩溃

它的工作方式是通过字符串测试来查看一系列单词是否适合标签的宽度。当计算当前范围过宽时,它会将最后一个拟合范围记录为一条线

我不认为这是有效的。更好的方法可能只是实现您自己的UILabel

@interface UILabel (Extensions)

- (NSArray*) lines;

@end

@implementation UILabel (Extensions)

- (NSArray*) lines
{
    if ( self.lineBreakMode != UILineBreakModeWordWrap )
    {
        return nil;
    }

    NSMutableArray* lines = [NSMutableArray arrayWithCapacity:10];

    NSCharacterSet* wordSeparators = [NSCharacterSet whitespaceAndNewlineCharacterSet];

    NSString* currentLine = self.text;
    int textLength = [self.text length];

    NSRange rCurrentLine = NSMakeRange(0, textLength);
    NSRange rWhitespace = NSMakeRange(0,0);
    NSRange rRemainingText = NSMakeRange(0, textLength);
    BOOL done = NO;
    while ( !done )
    {
        // determine the next whitespace word separator position
        rWhitespace.location = rWhitespace.location + rWhitespace.length;
        rWhitespace.length = textLength - rWhitespace.location;
        rWhitespace = [self.text rangeOfCharacterFromSet: wordSeparators options: NSCaseInsensitiveSearch range: rWhitespace];
        if ( rWhitespace.location == NSNotFound )
        {
            rWhitespace.location = textLength;
            done = YES;
        }

        NSRange rTest = NSMakeRange(rRemainingText.location, rWhitespace.location-rRemainingText.location);

        NSString* textTest = [self.text substringWithRange: rTest];

        CGSize sizeTest = [textTest sizeWithFont: self.font forWidth: 1024.0 lineBreakMode: UILineBreakModeWordWrap];
        if ( sizeTest.width > self.bounds.size.width )
        {
            [lines addObject: [currentLine stringByTrimmingCharactersInSet:wordSeparators]];
            rRemainingText.location = rCurrentLine.location + rCurrentLine.length;
            rRemainingText.length = textLength-rRemainingText.location;
            continue;
        }

        rCurrentLine = rTest;
        currentLine = textTest;
    }

    [lines addObject: [currentLine stringByTrimmingCharactersInSet:wordSeparators]];

    return lines;
}

@end
这样使用:

NSArray* lines = [_theLabel lines];

int count = [lines count];

要计算
UILabel
在包装文本后的行数,您需要找到
UILabel
字体的前导(行高)(
label.font.leading
),然后将多行
UILabel
的高度除以每行的高度,得到行数

下面是一个例子:

- (void)viewDidLoad {

    [super viewDidLoad];

    UILabel *label = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease];
    label.numberOfLines = 0;
    label.lineBreakMode = UILineBreakModeWordWrap;  
    label.text = @"Some really really long string that will cause the label's text to wrap and wrap and wrap around. Some really really long string that will cause the label's text to wrap and wrap and wrap around.";

    CGRect frame = label.frame;
    frame.size.width = 150.0f;
    frame.size = [label sizeThatFits:frame.size];
    label.frame = frame;

    CGFloat lineHeight = label.font.leading;
    NSUInteger linesInLabel = floor(frame.size.height/lineHeight);
    NSLog(@"Number of lines in label: %i", linesInLabel);

    [self.view addSubview:label];

}
或者,您可以用两行代码来完成:

[label sizeToFit];
int numLines = (int)(label.frame.size.height/label.font.leading);

只需调用下面的方法并传递
UILabel
UITextView

-(NSInteger)getNumberOfLinesInLabelOrTextView:(id)obj
{
    NSInteger lineCount = 0;
    if([obj isKindOfClass:[UILabel class]])
    {
        UILabel *label = (UILabel *)obj;

       // This method is deprecated in iOS 7.0 or later 
       // CGSize requiredSize = [label.text sizeWithFont:label.font constrainedToSize:label.frame.size lineBreakMode:label.lineBreakMode]; 

        CGSize requiredSize = [label.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(label.frame), CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:label.font} context:nil].size;

        int charSize = label.font.leading;
        int rHeight = requiredSize.height;

        lineCount = rHeight/charSize;
    }
    else if ([obj isKindOfClass:[UITextView class]])
    {
        UITextView *textView = (UITextView *)obj;
        lineCount = textView.contentSize.height / textView.font.leading;
    }

    return lineCount;
}
现在调用此方法:-

NSLog(@"%d",[self getNumberOfLinesInLabelOrTextView:label]);
NSLog(@"%d",[self getNumberOfLinesInLabelOrTextView:textView]);
println("%d \(self.getNumberOfLinesInLabelOrTextView(textView))")
println("%d \(self.getNumberOfLinesInLabelOrTextView(label))")
更新:SWIFT代码

func getNumberOfLinesInLabelOrTextView(obj:AnyObject) -> NSInteger {

    var lineCount: NSInteger = 0
    if (obj.isKindOfClass(UILabel)) {

        let label: UILabel = obj as! UILabel
        let requiredSize: CGSize = (label.text)!.boundingRectWithSize(CGSizeMake(CGRectGetWidth(label.frame), CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: label.font], context: nil).size
        let charSize: CGFloat = label.font.leading
        let rHeight: CGFloat = requiredSize.height
        lineCount = (NSInteger)(rHeight/charSize)
    }
    else if (obj.isKindOfClass(UITextView)){

        let textView: UITextView = obj as! UITextView
        lineCount = (NSInteger)(textView.contentSize.height / textView.font.leading)
    }

    return lineCount
}
现在调用此方法:-

NSLog(@"%d",[self getNumberOfLinesInLabelOrTextView:label]);
NSLog(@"%d",[self getNumberOfLinesInLabelOrTextView:textView]);
println("%d \(self.getNumberOfLinesInLabelOrTextView(textView))")
println("%d \(self.getNumberOfLinesInLabelOrTextView(label))")

注意:
前导
-使用线宽。不返回实际的前导。将在将来正式弃用。

对于Xcode 7和以上,TIGER的答案需要更新以下代码:

-(NSInteger)getNumberOfLinesInLabelOrTextView:(id)obj
{
    NSInteger lineCount = 0;
    if([obj isKindOfClass:[UILabel class]])
    {
        UILabel *label = (UILabel *)obj;
        CGSize requiredSize = [label.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(label.frame), CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:label.font} context:nil].size;

        int charSize = label.font.leading;
        // now listen , you need to set the text or label with only 1 
        // then nslog(@"%d",charSize);
        // then change the line int charSize = label.font.leading; into 
        // int charSize = the printed value in case of 1 line
        int rHeight = requiredSize.height;

        lineCount = rHeight/charSize;
    }
    else if ([obj isKindOfClass:[UITextView class]])
    {
        UITextView *textView = (UITextView *)obj;
        lineCount = textView.contentSize.height / textView.font.leading;
    }

    return lineCount;
}

这只有在您使用相同的字体和大小时才起作用,这不是一个明智的举动,但它帮助了我,我想将其作为我知道的当前解决方案来分享


要计算UILabel的行数,在包装文本后,需要将多行UILabel的高度除以每行的高度(
ascender

在尝试Adolfo的答案时,由于某种原因,
label.font.leading
返回0.0,因此我使用了
label.font.ascender
,它返回从基线到
UILabel
框架顶部的高度。见下图


感谢汤姆斯威夫特的支持。。。这种方法在某些情况下是有效的,但它确实给了我很大的帮助,我正在基于您的代码开发一种更为防弹的解决方案。再次感谢!很好的解决方案,汤姆斯威夫特。但它对我不起作用,它总是一行上的文本,尽管int计数有时是9、10或20。我的代码:self.labelDescription.text=event.description;self.labelDescription.lineBreakMode=UILineBreakModeWordWrap;self.labelDescription.font=[UIFont fontWithName:@“Helvetica”大小:13.0];NSArray*行=[self.labelDescription行];整数计数=[行计数];self.labelDescription.numberOfLines=计数;很好的解决方案,但对我来说,最后两行总是一样的。我通过添加currentLine=[self.text substringWithRange:rRemainingText];在继续之前;啊,这很聪明。肯定比我的解决方案简单!请注意,“leading”发音为“ledding”。(与“Led Zepplin”一模一样,而不是“跟随领袖”一模一样。)它只是指金属Led(即原子物质Pb)——这个词来源于早期的印刷术,当时你在字母之间放上Led条来创造Led。谢谢。。。。[标签尺寸合适];int numLines=(int)(label.frame.size.height/label.font.leading);为Method工作这很好,但当我将xcode更新为7时,lineCount=rHeight/charSize;上显示“exc_算术代码=exc_i386_div”错误。所以我做了lineCount=rHeight/1;现在它开始工作了。如果我错了,请引导我改正:)