2010-11-02 20 views
18

Tôi có một UILabel có kích thước được tính bằng phương pháp sizeWithFont:. Chế độ ngắt dòng được đặt thành UILineBreakModeWordWrap (cùng một cờ được sử dụng khi tính kích thước với sizeWithFont:) ...Các dòng kết quả của UILabel với UILineBreakModeWordWrap

Mọi thứ hoạt động tốt, nhãn được định cỡ đúng và hiển thị văn bản của tôi theo yêu cầu.

Bây giờ tôi cần biết các dòng được sử dụng để hiển thị nhãn (hoặc các dòng được tạo khi sử dụng sizeWithFont:). Về mặt kỹ thuật, tôi có thể viết việc triển khai dòng của riêng mình dựa trên khoảng trắng/dấu mũ, nhưng sau đó nó sẽ không được đảm bảo giống như cách triển khai của Apple và do đó các dòng kết quả sẽ không được sử dụng để tính kích thước văn bản , không bao giờ thực tế tái tạo bánh xe.

Lý tưởng nhất, tôi sẽ chuyển chuỗi của mình, chỉ định chế độ chiều rộng và ngắt dòng và nhận được một chuỗi các chuỗi đại diện cho các dòng hình ảnh của văn bản.

Bất kỳ ý tưởng nào làm cho điều này xảy ra theo cách thanh lịch nhất?

Trả lời

24

Tôi không nghĩ có bất kỳ viên đạn bạc nào cho việc này.

Đây là phương pháp danh mục có vẻ hoạt động đối với một số trường hợp thử nghiệm cơ bản mà tôi đã ném vào đó. Không đảm bảo nó sẽ không phá vỡ với một cái gì đó phức tạp!

Cách hoạt động là di chuyển qua thử nghiệm chuỗi để xem một dải từ có vừa với chiều rộng của nhãn hay không. Khi nó tính toán phạm vi hiện tại quá rộng, nó ghi lại phạm vi phù hợp cuối cùng dưới dạng một dòng.

Tôi không tuyên bố điều này là hiệu quả. Một cách tốt hơn có thể chỉ để được thực hiện UILabel của riêng bạn ...

@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 

sử dụng như thế này:

NSArray* lines = [_theLabel lines]; 

int count = [lines count]; 
+1

Cảm ơn TomSwift cho đầu vào của bạn ... Đây loại công trình đối với một số trường hợp, nhưng nó chắc chắn đã cho tôi một sự thúc đẩy lớn, tôi đang làm việc trên một giải pháp thêm bằng chứng đạn dựa trên mã của bạn . Cảm ơn một lần nữa! – Nick

+0

Trường hợp nào đã phá vỡ nó? – TomSwift

+0

Giải pháp Nice TomSwift. Nhưng nó không hiệu quả đối với tôi, nó luôn luôn là văn bản trên một dòng mặc dù int đếm đôi khi là 9, 10 hoặc 20. Mã của tôi: \t self.labelDescription.text = event.description; \t self.labelDescription.lineBreakMode = UILineBreakModeWordWrap; \t self.labelDescription.font = [UIFont fontWithName: @ "Helvetica" size: 13.0]; \t \t NSArray * lines = [self.labelDescription lines]; \t \t số đếm = [số dòng]; \t self.labelDescription.numberOfLines = count; –

38

Để tính số dòng mà một UILabel có sau khi gói đó là văn bản mà bạn sẽ cần để tìm hàng đầu (chiều cao dòng) của phông chữ UILabel của bạn (label.font.leading) và sau đó chia chiều cao của nhiều dòng UILabel theo chiều cao của mỗi dòng để mang lại số dòng.

Dưới đây là một ví dụ:

- (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]; 

} 

Hoặc, bạn có thể làm điều đó trong hai dòng:

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

ah, điều này rất thông minh. đơn giản hơn giải pháp của tôi, chắc chắn! – TomSwift

+3

Lưu ý rằng ** "hàng đầu" ** được phát âm là "ledding". Nó chỉ đơn giản có nghĩa là kim loại, dẫn (tức là, chất nguyên tử Pb) - từ này xuất phát từ những ngày đầu của kiểu chữ khi bạn đặt các dải led giữa các chữ cái để tạo ra, tốt, ledding. – Fattie

+0

Cảm ơn .... [label sizeToFit]; int numLines = (int) (label.frame.size.height/label.font.leading); làm việc cho tôi –

11

Chỉ cần gọi dưới phương pháp và thông qua một trong hai UILabel hoặc 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; 
} 

Bây giờ gọi phương thức này: -

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

CẬP NHẬT: SWIFT CODE

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 
} 

Bây giờ gọi phương pháp này: -

println("%d \(self.getNumberOfLinesInLabelOrTextView(textView))") 
println("%d \(self.getNumberOfLinesInLabelOrTextView(label))") 

Lưu ý: leading - sử dụng lineHeight. không trả lại hàng đầu thực tế. sẽ bị phản đối chính thức trong tương lai.

+0

Điều này làm việc tốt nhưng khi tôi cập nhật xcode đến 7 nó hiển thị "exc_arithmetic code = exc_i386_div" lỗi trên dòng lineCount = rHeight/charSize; . Vì vậy, tôi đã làm lineCount = rHeight/1; bây giờ nó đang hoạt động. Nếu tôi sai hướng dẫn tôi đúng một :) – user3589771

0

cho Xcode 7 và lên câu trả lời TheTiger của cần cập nhật nhận xét về đoạn code dưới đây:

-(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; 
} 

này sẽ chỉ làm việc nếu bạn đang sử dụng cùng một phông chữ và kích thước, nó không phải là một động thái thông minh nhưng nó giúp tôi và tôi muốn chia sẻ nó như là giải pháp hiện tại tôi biết

0

Cập nhật cho Swift 3

để tính toán số lượng dòng UILabel có, sau khi gói văn bản của nó, bạn cần phải di vide chiều cao của UILabel nhiều dòng của bạn theo chiều cao của mỗi dòng (ascender).

Khi cố gắng trả lời Adolfo của, đối với một số lý do, label.font.leading trở 0.0, vì vậy tôi sử dụng label.font.ascender, mà trả về chiều cao từ đường cơ sở để phía trên cùng của khung 's UILabel. Nhìn bức ảnh bên dưới.

enter image description here

//Makes label go to another line if necessary 
label.numberOfLines = 0 //Set num of lines to infinity 
label.lineBreakMode = .byWordWrapping 
label.sizeToFit() 
let numLines = Int(label.frame.size.height/label.font.ascender) 
Các vấn đề liên quan