Kích thước UILabelToFit không hoạt động với autosayout ios6


152

Làm cách nào để tôi định cấu hình lập trình (và theo phương thức nào) một UILabel có chiều cao phụ thuộc vào văn bản của nó? Tôi đã cố gắng thiết lập nó bằng cách sử dụng kết hợp Storyboard và mã, nhưng không có kết quả. Mọi người đề nghị sizeToFittrong khi thiết lập lineBreakModenumberOfLines. Tuy nhiên, không có vấn đề nếu tôi đặt mã trong viewDidLoad:, viewDidAppear:hoặc viewDidLayoutSubviewstôi có thể không nhận được nó để làm việc. Hoặc là tôi làm cho hộp quá nhỏ đối với văn bản dài và nó không phát triển hoặc tôi làm cho nó quá lớn và nó không co lại.


FWIW cùng mã: Tôi không cần sử dụng label.sizeToFit()trong Xcode / viewControll, các ràng buộc là đủ. đã không tạo nhãn trong Sân chơi . Cho đến nay, cách duy nhất tôi thấy nó hoạt động trong Playground là làmlabel.sizeToFit()
Mật ong

Câu trả lời:


407

Xin lưu ý rằng trong hầu hết các trường hợp , giải pháp của Matt hoạt động như mong đợi. Nhưng nếu nó không hiệu quả với bạn, xin vui lòng, đọc thêm.

Để làm cho nhãn của bạn tự động thay đổi kích thước chiều cao, bạn cần làm như sau:

  1. Đặt các ràng buộc bố cục cho nhãn
  2. Đặt ràng buộc chiều cao với mức độ ưu tiên thấp. Nó phải thấp hơn ContentCompressionResistanceP Warriority
  3. Đặt sốOfLines = 0
  4. Đặt ContentHuggingP Warriority cao hơn mức ưu tiên chiều cao của nhãn
  5. Đặt ưa thíchMaxLayoutWidth cho nhãn. Giá trị đó được sử dụng bởi nhãn để tính chiều cao của nó

Ví dụ:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

Sử dụng Trình tạo giao diện

  1. Thiết lập bốn ràng buộc. Hạn chế chiều cao là bắt buộc. nhập mô tả hình ảnh ở đây

  2. Sau đó, đi đến trình kiểm tra thuộc tính của nhãn và đặt số dòng thành 0. nhập mô tả hình ảnh ở đây

  3. Chuyển đến trình kiểm tra kích thước của nhãn và tăng ContentHuggingP Warriority và ContentCompressionResistanceP Warriority dọc.
    nhập mô tả hình ảnh ở đây

  4. Chọn và chỉnh sửa ràng buộc chiều cao.
    nhập mô tả hình ảnh ở đây

  5. Và giảm ưu tiên hạn chế chiều cao.
    nhập mô tả hình ảnh ở đây

Thưởng thức. :)


4
ĐÚNG! Đây chính xác là câu trả lời tôi đang tìm kiếm. Điều duy nhất tôi cần làm là đặt nội dungHuggingP Warriority và contentCompressionResistanceP Warriority thành bắt buộc. Tôi có thể làm tất cả trong IB! Cảm ơn bạn rất nhiều.
Circuitlego

43
Bạn đang xem xét lại điều này. Đặt preferredMaxLayoutWidthhoặc ghim chiều rộng của nhãn (hoặc cạnh phải và trái của nhãn). Đó là tất cả! Sau đó, nó sẽ tự động phát triển và thu hẹp theo chiều dọc để phù hợp với nội dung của nó.
matt

Tôi đã phải đặt thuộc tính ưa thíchMaxLayoutWidth + ghim chiều rộng của nhãn. Hoạt động như một bùa mê :)
MartinMoizard

ưa thíchMaxLayoutWidth và / hoặc ghim bên trái và bên phải là không tuyệt đối. Các ưu tiên ôm và nén nội dung sẽ luôn hoạt động miễn là các ưu tiên của chúng cao hơn các ràng buộc còn lại.
Eric Alford

2
^ Và cuối cùng tôi đã tìm ra lý do tại sao, Có thể đáng để đề cập, khi bạn có ô dính ở dưới cùng của chế độ xem, bạn cần đặt mức độ ưu tiên của ràng buộc "xuống dưới" xuống dưới 1000 tôi đặt nó vào 750 và mọi thứ đều hoạt động hoàn hảo Tôi đoán nó thu nhỏ tầm nhìn.
Mathijs

65

Trong iOS 6, sử dụng tính năng tự động thanh toán, nếu các cạnh (hoặc chiều rộng) của UILabel được ghim, nó sẽ tự động phát triển và co lại theo chiều dọc để phù hợp với nội dung của nó, không có mã nào cả và không gây rối với khả năng chống nén hay bất cứ điều gì. Nó là đơn giản chết.

Trong trường hợp phức tạp hơn, chỉ cần đặt nhãn preferredMaxLayoutWidth.

Dù bằng cách nào, điều đúng sẽ tự động xảy ra.


12
Bạn cũng cần đảm bảo đặt numberOfLines thành 0 nếu không bạn sẽ không nhận được gói.
devongovett

2
Điều này là không đủ cho tôi. Cũng cần điểm 2 từ câu trả lời của @ Mark.
Danyal Aytekin

cũng có thể làm cho nhãn phát triển tự động trên một số dòng mà không cần viết mã?
Noor

Điều này ít phức tạp hơn nhiều so với câu trả lời được chấp nhận. Tôi đã thực hiện hai ví dụ ( ở đâyở đây ) minh họa câu trả lời này.
Suragch

@Suragch Sử dụng các ràng buộc này hoạt động. Nhưng nó không hoạt động với cùng một mã trong Playground . Trong sân chơi bạn phải cólabel.sizeToFit()
Mật ong

42

Mặc dù câu hỏi nêu lập trình, gặp phải vấn đề tương tự và thích làm việc trong Trình tạo giao diện, tôi nghĩ rằng có thể hữu ích khi thêm vào các câu trả lời hiện có bằng giải pháp Trình tạo giao diện.

Điều đầu tiên là quên đi sizeToFit. Bố cục tự động sẽ xử lý việc này thay mặt bạn dựa trên kích thước nội dung bên trong.

Do đó, vấn đề là làm thế nào để có một nhãn phù hợp với nội dung của nó với Bố cục tự động? Cụ thể - bởi vì câu hỏi đề cập đến nó - chiều cao. Lưu ý rằng các nguyên tắc tương tự áp dụng cho chiều rộng.

Vì vậy, hãy bắt đầu với một ví dụ UILabel có chiều cao được đặt thành cao 41px:

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy trong màn hình lấy ở trên, "This is my text"có phần đệm ở trên và bên dưới. Đó là phần đệm giữa chiều cao của UILabel và nội dung của nó, văn bản.

Nếu chúng ta chạy ứng dụng trong trình giả lập, chắc chắn, chúng ta sẽ thấy điều tương tự:

nhập mô tả hình ảnh ở đây

Bây giờ, hãy chọn UILabel trong Trình tạo giao diện và xem các cài đặt mặc định trong Trình kiểm tra kích thước:

nhập mô tả hình ảnh ở đây

Lưu ý các ràng buộc được tô sáng ở trên. Đó là Ưu tiên ôm nội dung . Như Erica Sadun mô tả nó trong Giao diện tự động tuyệt vời của iOS được phân loại , đây là:

cách một khung nhìn thích tránh phần đệm thêm xung quanh nội dung cốt lõi của nó

Đối với chúng tôi, với UILabel, nội dung cốt lõi là văn bản.

Ở đây chúng tôi đi đến trung tâm của kịch bản cơ bản này. Chúng tôi đã đưa ra nhãn văn bản của chúng tôi hai ràng buộc. Họ xung đột. Một người nói "chiều cao phải bằng 41 pixel" . Người khác nói "ôm tầm nhìn vào nội dung của nó để chúng tôi không có thêm phần đệm" . Trong trường hợp của chúng tôi, hãy xem chế độ xem văn bản để chúng tôi không có thêm phần đệm.

Bây giờ, với Bố cục tự động, với hai hướng dẫn khác nhau có thể làm những việc khác nhau, thời gian chạy phải chọn cái này hoặc cái kia. Nó không thể làm cả hai. Nhãn UIL không thể cao cả 41 pixel không có phần đệm.

Cách giải quyết vấn đề này là bằng cách chỉ định mức độ ưu tiên. Một hướng dẫn phải có mức độ ưu tiên cao hơn hướng dẫn khác. Nếu cả hai hướng dẫn đều nói những điều khác nhau và có cùng mức độ ưu tiên, một ngoại lệ sẽ xảy ra.

Vì vậy, hãy cho nó đi. Hạn chế chiều cao của tôi có mức độ ưu tiên là 1000 , được yêu cầu . Chiều cao ôm nội dung là 250 , yếu . Điều gì xảy ra nếu chúng ta giảm mức ưu tiên ràng buộc chiều cao xuống còn 249 ?

nhập mô tả hình ảnh ở đây

Bây giờ chúng ta có thể thấy điều kỳ diệu bắt đầu xảy ra. Hãy thử trong sim:

nhập mô tả hình ảnh ở đây

Tuyệt vời! Nội dung ôm nhau đạt được. Chỉ vì ưu tiên chiều cao 249 nhỏ hơn ưu tiên ôm nội dung 250 . Về cơ bản, tôi đang nói "chiều cao tôi chỉ định ở đây ít quan trọng hơn chiều cao tôi đã chỉ định cho nội dung ôm" . Vì vậy, nội dung ôm chiến thắng.

Dòng dưới cùng, làm cho nhãn phù hợp với văn bản có thể đơn giản như chỉ định ràng buộc chiều cao - hoặc chiều rộng - và cài đặt chính xác mức độ ưu tiên liên quan đến ràng buộc ưu tiên nội dung của trục đó.

Sẽ để lại làm tương đương cho chiều rộng như một bài tập cho người đọc!


3
Cảm ơn rất nhiều cho lời giải thích tuyệt vời của bạn! Cuối cùng tôi hiểu nội dung ưu tiên ôm.
kernix

Bạn có thể vui lòng giải thích ưu tiên kháng nén nội dung là gì? Cảm ơn!
kernix

2
Trả lời tối đa! Có cách nào đó để hạn chế số lượng dòng làm việc theo cách đó?
rafaeljuzo

7

Thông báo trong iOS7 sizeToFit cũng không hoạt động - có lẽ giải pháp cũng có thể giúp bạn

[textView sizeToFit];
[textView layoutIfNeeded];

1
@Rambatino Điều này làm việc với tôi. Thêm layoutIfNeededkhi bạn cần setNeedsUpdateConstraints. Nhưng tình hình có thể hơi khác một chút.
Gon

Điều này làm việc tốt nhất cho tôi khi tôi làm một popover. Mặc dù vậy, tôi cần phải thực hiện bố cục. Trước tiên
Jason

4

Một tùy chọn khác để đảm bảoMaxLayoutWidth của nhãn được giữ đồng bộ với chiều rộng của nhãn:

#import "MyLabel.h"

@implementation MyLabel

-(void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];

    // This appears to be needed for iOS 6 which doesn't seem to keep
    // label preferredMaxLayoutWidth in sync with its width, which 
    // means the label won't grow vertically to encompass its text if 
    // the label's width constraint changes.
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

@end

4

Tôi cảm thấy mình nên đóng góp vì phải mất một thời gian để tìm ra giải pháp phù hợp:

  • Mục tiêu là để cho Bố cục tự động thực hiện công việc của nó mà không cần gọi sizeToFit (), chúng tôi sẽ thực hiện điều này bằng cách chỉ định các ràng buộc đúng:
  • Chỉ định các ràng buộc không gian trên cùng, dưới cùng và hàng đầu / theo dõi trên UILabel của bạn
  • Đặt số lượng thuộc tính dòng thành 0
  • Tăng mức độ ưu tiên ôm nội dung lên 1000
  • Giảm mức độ ưu tiên kháng nén nội dung xuống 500
  • Trên ràng buộc vùng chứa dưới cùng của bạn, hạ mức ưu tiên xuống 500

Về cơ bản, điều xảy ra là bạn nói với UILabel của mình rằng mặc dù nó có một ràng buộc về chiều cao cố định, nó có thể phá vỡ ràng buộc để làm cho nó nhỏ hơn để ôm lấy nội dung (ví dụ nếu bạn có một dòng duy nhất), nhưng nó không thể phá vỡ các ràng buộc để làm cho nó lớn hơn.


3

Trong trường hợp của tôi, tôi đã tạo một lớp con UIView có chứa một UILabel (có độ dài không xác định). Trong iOS7, mã rất đơn giản: đặt các ràng buộc, đừng lo lắng về khả năng chống ôm hoặc nén nội dung và mọi thứ đều hoạt động như mong đợi.

Nhưng trong iOS6, UILabel luôn được cắt thành một dòng duy nhất. Không có câu trả lời nào ở trên làm việc cho tôi. Nội dung cài đặt kháng ôm và nén đã bị bỏ qua. Giải pháp duy nhất ngăn chặn việc cắt xén là bao gồm mộtMaxLayoutWidth ưa thích trên nhãn. Nhưng tôi không biết nên đặt chiều rộng ưa thích là gì, vì kích thước của chế độ xem chính của nó không xác định (thực sự, nó sẽ được xác định bởi nội dung).

Cuối cùng tôi đã tìm thấy giải pháp ở đây . Vì tôi đang làm việc trên chế độ xem tùy chỉnh, tôi chỉ có thể thêm phương thức sau để đặt độ rộng bố cục ưa thích sau khi các ràng buộc đã được tính một lần, sau đó tính toán lại chúng:

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}

Đây là kịch bản chính xác mà tôi đã có đôi khi thật vui khi biết bạn không cô đơn.
daveMac

Adam, tôi đang vật lộn với những gì bạn nói đã hoạt động hoàn hảo trong ios7. Tôi có một ô tùy chỉnh với uiview và uilabel. Tôi có thể có được nhãn phù hợp với nội dung nhưng chế độ xem không, cho dù tôi có đặt ra ràng buộc nào. Làm thế nào bạn có được nó để làm việc? Tôi thề tôi đã thử mọi cách nhưng nó không lấy chiều cao của nhãn
denikov

3

Tôi đã thêm UILabelchương trình và trong trường hợp của tôi là đủ:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0

2

tôi đã giải quyết với xCode6 khi đặt "Chiều rộng ưa thích" thành Tự động và ghim đầu nhãn, dẫn đầu và theo dõi nhập mô tả hình ảnh ở đây


0
UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));

0

Tôi cũng gặp phải vấn đề này với một lớp con UIView có chứa một UILabel như là một phần tử bên trong của nó. Ngay cả khi tự động thanh toán và thử tất cả các giải pháp được đề xuất, nhãn sẽ không thắt chặt chiều cao của nó với văn bản. Trong trường hợp của tôi, tôi chỉ muốn nhãn là một dòng.

Dù sao, điều làm việc với tôi là thêm một ràng buộc về chiều cao cần thiết cho UILabel và đặt nó theo cách thủ công đến độ cao chính xác khi gọi intinsicContentSize. Nếu bạn không có UILabel chứa trong một UIView khác, bạn có thể thử phân lớp UILabel và cung cấp cách triển khai tương tự bằng cách trước tiên đặt giới hạn chiều cao và sau đó trả về
[super BarsinsicContentSize]; thay vì [self.containerview intinsiceContentSize]; giống như tôi làm dưới đây, cụ thể cho lớp con UIView của tôi.

- (CGSize)intrinsicContentSize
{
    CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
    self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
    return [self.containerView intrinsicContentSize];

}

Hoạt động hoàn hảo ngay bây giờ trên iOS 7 và iOS 8.


Điều đáng chú ý là nếu bạn đã thiết lập chế độ xem chính xác (nghĩa là các ràng buộc của bạn là chính xác và bạn đã thiết lập mọi thứ trong các giai đoạn chính xác trong vòng đời của chế độ xem), bạn không bao giờ phải ghi đè intrinsicContentSize. Thời gian chạy sẽ có thể tính toán điều này dựa trên các ràng buộc thiết lập chính xác của bạn.
John Rogers

Theo lý thuyết là đúng, nhưng chúng tôi không có quyền truy cập vào tất cả các API và triển khai API riêng của Apple và chúng không thể sai được và có lỗi trong mã của họ.
n8tr

... nhưng [super intinsicContentSize] nên quan tâm đến nó, đó là những gì tôi đang nói. Nếu bạn đã thực hiện bố trí tự động của bạn một cách chính xác.
John Rogers

0

Một giải pháp hiệu quả với tôi; Nếu UILabel của bạn có chiều rộng cố định, hãy thay đổi ràng buộc từ constant =sang constant <=trong tệp giao diện của bạn

nhập mô tả hình ảnh ở đây


-1

Trong trường hợp của tôi khi sử dụng các nhãn trong UITableViewCell, nhãn tại sẽ thay đổi kích thước nhưng chiều cao sẽ vượt quá chiều cao của ô bảng. Đây là những gì làm việc cho tôi. Tôi đã làm theo Max MacLeod, và sau đó đảm bảo chiều cao của ô được đặt thành UITableViewAutomaticDimension.

Bạn có thể thêm cái này vào trong init hoặc awakeFromNib của bạn,

self.tableView.rowHeight = UITableViewAutomaticDimension.  

Trong bảng phân cảnh, chọn ô, mở Trình kiểm tra kích thước và đảm bảo chiều cao hàng được đặt thành "Mặc định" bằng cách chọn hộp kiểm 'Tùy chỉnh'.

Có một vấn đề trong 8.0 cũng yêu cầu nó phải được đặt trong mã.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.