2013-03-19 16 views
15

Vì vậy, tôi đã thiết lập chế độ xem của mình bằng IB sao cho nhãn văn bản này phù hợp với đầu hình thu nhỏ thông qua các ràng buộc.Theo chiều dọc Căn chỉnh văn bản UILabel với các ràng buộc và không quấn (bố cục tự động, một dòng)

enter image description here

Tuy nhiên như chúng ta biết, bạn không thể theo chiều dọc gắn kết văn bản trong một UILabel. Văn bản của tôi cập nhật kích thước phông chữ dựa trên độ dài của nội dung. Văn bản có kích thước đầy đủ trông tuyệt vời, trong khi văn bản nhỏ thì thấp hơn đáng kể trên chế độ xem.

enter image description here

Các existing solution liên quan đến một trong hai gọi sizeToFit hoặc cập nhật khung của UILabel để phù hợp với chiều cao của văn bản. Thật không may, giải pháp thứ hai (mặc dù xấu xí) không hoạt động tốt với các ràng buộc mà bạn không phải cập nhật khung. Các giải pháp trước đây về cơ bản không hoạt động khi bạn cần phải có autoshrink văn bản cho đến khi nó cắt ngắn. (Vì vậy, nó không hoạt động với một số lượng hạn chế các dòng và autoshrink).

Bây giờ là tại sao kích thước nội tại (chiều cao) của uilabel không cập nhật như chiều rộng khi nó được đặt thành kích thước tự nhiên thông qua "Kích thước để vừa với nội dung" nằm ngoài tôi. Có vẻ như nó chắc chắn nên, nhưng nó không.

Vì vậy, tôi đang tìm kiếm các giải pháp thay thế. Theo như tôi thấy, bạn có thể phải đặt giới hạn chiều cao trên nhãn và điều chỉnh hằng số chiều cao sau khi tính chiều cao của văn bản. Bất cứ ai có một giải pháp tốt?

+0

@ hans-sjunnesson: bạn đã thử tự động thu nhỏ với điều chỉnh đường cơ sở của 'Không'? –

+0

@ JörnEyrich trong khi đó sẽ làm cho văn bản dính vào đầu khung, khung thực tế của UILabel không co lại. Điều đó có nghĩa là nếu bạn có một nhãn phụ bên dưới nhãn đó, nhãn phụ sẽ không làm theo nhãn khi nó co lại. –

+0

Kiểm tra http://stackoverflow.com/a/4942766/1039901 –

Trả lời

7

Vấn đề này là PITA thực để giải quyết. Nó không giúp công việc của API không được chấp nhận trong iOS7, hoặc rằng các API thay thế iOS7 bị hỏng. Blah!

Giải pháp của bạn tốt, tuy nhiên nó sử dụng API không dùng nữa (sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:) và không được gói gọn - bạn cần sao chép mã này xung quanh bất kỳ ô hoặc chế độ xem nào bạn muốn hành vi này. Về mặt cộng, nó khá hiệu quả! Một lỗi có thể là nhãn chưa được đặt ra khi bạn thực hiện phép tính, nhưng bạn thực hiện phép tính dựa trên chiều rộng của nó.

Tôi đề xuất bạn đóng gói hành vi này trong lớp con UILabel.Bằng cách đặt phép tính kích thước trong phương thức intrinsicContentSize bị ghi đè, nhãn sẽ tự động định kích thước. Tôi đã viết như sau, kết hợp mã của bạn sẽ thực thi trên iOS6 và phiên bản của tôi sử dụng API không được chấp nhận cho iOS7 trở lên:

@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 

Triển khai này không hoàn hảo. Tôi phải đảm bảo sử dụng baselineAdjustment == UIBaselineAdjustmentAlignCenters và tôi không chắc chắn 100% là tôi hiểu tại sao. Và tôi không hài lòng với những cái vòng mà tôi phải nhảy qua để có được chiều cao văn bản chính xác. Ngoài ra còn có một vài điểm khác biệt giữa những gì tính toán của tôi tạo ra và của bạn. Vui lòng chơi với nó và điều chỉnh khi cần thiết :)

API boundingRectWithSize:options:attributes:context API có vẻ khá là hỏng đối với tôi. Trong khi nó (chủ yếu!) Chính xác ràng buộc văn bản với kích thước đầu vào, nó không tính chiều cao chính xác! Chiều cao nó trả về dựa trên chiều cao dòng của phông chữ được cung cấp, ngay cả khi mở rộng quy mô. Tôi đoán đây là lý do tại sao UILabel không có hành vi này theo mặc định? Cách giải quyết của tôi là tính toán kích thước không bị giới hạn ở đó cả chiều cao và chiều rộng đều chính xác, sau đó sử dụng tỷ lệ giữa độ rộng hạn chế và không bị giới hạn để tính chiều cao chính xác cho kích thước bị hạn chế. Thật là một PITA. Có rất nhiều khiếu nại trong diễn đàn dev của Apple và ở đây trên SO chỉ ra rằng API này có một số vấn đề như thế này.

+0

Tôi cảm thấy như một sao Hỏa để hỏi nhưng PITA là gì? – Kuzgun

+1

Đau đớn trong một ... Chờ đợi, các siêu sao có lừa không? –

+0

Bạn nhận được tiền thưởng Tom. Mặc dù nó có thể cảm thấy như một hack, việc thực hiện thuộc về tính toán kích thước nội tại của nhãn. –

-3

Điều bạn đang tìm kiếm là hai dòng mã này.

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

và bạn cũng sẽ tìm thấy điều này trong Thanh tra thuộc tính trong "Đường ngắt" và "Đường".

+0

Không nếu bạn không muốn nó quấn. –

2

Vì vậy, tôi đã tìm thấy giải pháp thay thế. Đó là một chút xúc xắc, nhưng nó hoạt động.

Vì vậy, điều tôi đã làm là thêm giới hạn chiều cao vào dòng văn bản của tôi bằng IB và lấy tham chiếu đến văn bản đó trong chế độ xem của tôi.

Sau đó, trong layoutSubviews, tôi cập nhật chiều cao hạn chế của tôi dựa trên kích thước của phông chữ, mà tôi phải tính toán:

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

Lúc đầu, tôi chỉ đặt nó vào kích thước phông chữ thực tế, nhưng ngay cả với một điều chỉnh (* 1.2) nó vẫn cắt các kích thước phông chữ nhỏ hơn. Điều quan trọng là sử dụng CTFontGetBoundingBox với kích thước phông chữ được xác định từ tính toán của tôi.

Điều này thật không may, và tôi hy vọng có một cách tốt hơn. Có lẽ tôi nên chuyển sang gói.

1

TomSwift cảm ơn câu trả lời của bạn, tôi thực sự gặp khó khăn với vấn đề này.

Nếu ai đó vẫn nhận được hành vi kỳ lạ, tôi đã phải thay đổi:

intrinsicContentSize = CGSizeMake (inaccurateSize.width, accurateHeight);

để

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

thì nó hoạt động như sự quyến rũ.

Các vấn đề liên quan