iOS: UILabel nhiều dòng trong Bố cục tự động


183

Tôi gặp khó khăn khi cố gắng đạt được một số hành vi bố cục rất cơ bản với Bố cục tự động. Trình điều khiển xem của tôi trông như thế này trong IB:

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

Nhãn hàng đầu là nhãn tiêu đề, tôi không biết nó sẽ có bao nhiêu dòng. Tôi cần nhãn tiêu đề để hiển thị tất cả các dòng văn bản. Tôi cũng cần hai nhãn khác và hình ảnh nhỏ được đặt ngay bên dưới tiêu đề, tuy nhiên nó rất cao. Tôi đã đặt các ràng buộc khoảng cách dọc giữa các nhãn và hình ảnh nhỏ, cũng như một ràng buộc khoảng cách trên cùng giữa nhãn tiêu đề và giám sát của nó và một ràng buộc khoảng cách dưới cùng giữa hình ảnh nhỏ và giám sát của nó. UIView màu trắng không có giới hạn về chiều cao, do đó, nó phải kéo dài theo chiều dọc để chứa các phần phụ của nó. Tôi đã đặt số lượng dòng cho nhãn tiêu đề là 0.

Làm cách nào để có thể thay đổi nhãn tiêu đề để thay đổi kích thước cho phù hợp với số lượng dòng được yêu cầu bởi chuỗi? Tôi hiểu rằng tôi không thể sử dụng các phương thức setFrame vì tôi đang sử dụng Bố cục tự động. Và tôi phải sử dụng Bố cục tự động vì tôi cần những chế độ xem khác ở dưới nhãn tiêu đề (do đó có các ràng buộc).

Làm thế nào tôi có thể làm điều này xảy ra?


3
Tôi cũng đang chiến đấu với một vấn đề tương tự. Nhưng tôi vẫn đang cố gắng để có được nhãn hàng đầu để điều chỉnh chiều cao của nó một cách linh hoạt để phù hợp với nội dung. Làm thế nào bạn đạt được điều này?
jbandi

1
Vui lòng xem xét đánh dấu câu trả lời của @ mwhuss là câu trả lời được chấp nhận.
jemmons

1
Bạn đã đạt được kết quả cần thiết?
Aniruddha

kiểm tra điều này, bạn không cần thêm một dòng mã stackoverflow.com/a/36862795/4910767
Badal Shah

Câu trả lời:


254

Sử dụng -setPreferredMaxLayoutWidthtrên UILabelvà tự động thanh toán nên xử lý phần còn lại.

[label setPreferredMaxLayoutWidth:200.0];

Xem tài liệu UILabel trên preferMaxLayoutWidth .

Cập nhật:

Chỉ cần đặt heightràng buộc trong bảng phân cảnh thành Greater than or equal to, không cần thiết lậpPreferredMaxLayoutWidth.


8
Đẹp một, dù sao để làm điều này trong xây dựng giao diện?
Sjoerd Perfors 5/12/13

12
Đồng thời đặt giới hạn chiều cao trong IB thành Lớn hơn hoặc bằng ".
jowie

10
Nhắc nhở: hãy nhớ đặt thuộc tính numberOfLines.
Li Fumin

2
Đúng, sử dụng bất cứ điều gì bạn muốn chiều rộng tối đa là.
mwhuss

4
Xem stackoverflow.com/a/29180323/1529675 để biết cách xác định preferredMaxLayoutWidthvà xem devetc.org/code/2014/07/07/auto-layout-and-view-that-wrap.html để biết cách viết ngắn gọn nhưng đầy đủ thông tin, hoàn thành với GIF hoạt hình (không phải là bài viết của tôi, tôi đã tìm thấy nó thông qua Google)
tboyce12

213

Mở rộng số dòng đặt nhãn của bạn thành 0 và quan trọng hơn là bố trí tự động đặt chiều cao thành> = x. Bố trí tự động sẽ làm phần còn lại. Bạn cũng có thể chứa các yếu tố khác của bạn dựa trên yếu tố trước đó để định vị chính xác sau đó.

bố trí tự động


Nếu phương pháp này không phù hợp với bạn, vui lòng xem câu trả lời của Cory Imdieke về việc đảm bảo các chế độ xem tiếp theo không cấm Bố cục tự động thay đổi kích thước chế độ xem đa hướng (có thể).
Tom Howard

1
Đây là câu trả lời duy nhất có hiệu quả với tôi trong Ô xem bảng. Cũng hoạt động với số lượng hàng cố định (thay vì 0 / không giới hạn)
bgolson

Điều này không phù hợp với tôi với bộ chiều rộng tối đa ưa thích rõ ràng, vì vậy hãy đảm bảo rằng điều này được đặt thành tự động trong IB khi sử dụng kỹ thuật này. Chúc mừng
jmc 10/2/2015

Đặt chiều rộng tối đa tự động chỉ khả dụng trong iOS8. Theo hiểu biết của tôi, nó cũng sẽ tự động điều chỉnh chiều cao và theo kinh nghiệm của tôi, bạn không cần phải đặt giới hạn chiều cao để nó hoạt động. Điều này làm việc cho tôi bằng cách sử dụng một chiều rộng rõ ràng.
Tony

1
Điều này đã không làm việc cho tôi. Tôi tin stackoverflow.com/a/13032251/1529675 là câu trả lời đúng.
tboyce12

48

Nguồn: http://www.objc.io/su-3/advified-auto-layout-toolbox.html

Kích thước nội dung nội tại của văn bản nhiều dòng

Kích thước nội dung nội tại của UILabel và NSTextField không rõ ràng đối với văn bản nhiều dòng. Chiều cao của văn bản phụ thuộc vào chiều rộng của các dòng, vẫn chưa được xác định khi giải quyết các ràng buộc. Để giải quyết vấn đề này, cả hai lớp đều có một thuộc tính mới gọi là preferMaxLayoutWidth, chỉ định độ rộng dòng tối đa để tính kích thước nội dung bên trong.

Vì chúng ta thường không biết trước giá trị này, chúng ta cần thực hiện một cách tiếp cận hai bước để có được quyền này. Đầu tiên chúng ta để Auto Layout thực hiện công việc của mình và sau đó chúng ta sử dụng khung kết quả trong pass layout để cập nhật lại chiều rộng tối đa ưa thích và bố trí kích hoạt lại.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Cuộc gọi đầu tiên đến [super layoutSubview] là cần thiết để nhãn có được bộ khung của nó, trong khi cuộc gọi thứ hai là cần thiết để cập nhật bố cục sau khi thay đổi. Nếu chúng tôi bỏ qua cuộc gọi thứ hai, chúng tôi sẽ gặp lỗi NSIternalInconsistencyException, vì chúng tôi đã thực hiện các thay đổi trong đường dẫn bố cục yêu cầu cập nhật các ràng buộc, nhưng chúng tôi đã không kích hoạt lại bố cục.

Chúng ta cũng có thể làm điều này trong một lớp con nhãn chính nó:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

Trong trường hợp này, trước tiên chúng ta không cần gọi [super layoutSubview], vì khi layoutSubview được gọi, chúng ta đã có một khung trên chính nhãn đó.

Để thực hiện điều chỉnh này từ cấp độ của trình điều khiển chế độ xem, chúng tôi nối vào viewDidLayoutSubview. Tại thời điểm này, các khung của vượt qua Bố cục tự động đầu tiên đã được đặt và chúng ta có thể sử dụng chúng để đặt chiều rộng tối đa ưa thích.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Cuối cùng, hãy đảm bảo rằng bạn không có ràng buộc về chiều cao rõ ràng trên nhãn có mức ưu tiên cao hơn mức ưu tiên kháng nén nội dung của nhãn. Nếu không, nó sẽ thổi phồng chiều cao tính toán của nội dung. Đảm bảo kiểm tra tất cả các ràng buộc có thể ảnh hưởng đến chiều cao của nhãn.


cảm ơn bạn cảm ơn bạn cảm ơn bạn không chỉ mã, mà quan trọng hơn là lời giải thích và các ví dụ về cách làm điều này không chỉ trong một lớp con, mà còn từ trình điều khiển xem.
djibouti33

Tôi đang thử điều này trong trình điều khiển chế độ xem của mình và viewDidLayoutSubview sẽ được gọi sau khi viewWillAppear và viewDidAppear. Sau viewDidAppear, sẽ có đèn flash khi nhãn được thay đổi kích thước chính xác. Có cách nào để tránh điều này? Có cách nào để thay đổi kích thước để hoàn thành trước khi người dùng nhìn thấy bất cứ điều gì không? trong trường hợp của tôi, các nhãn nhiều dòng của tôi nằm trong bảngHeadView và vì vậy tôi cũng thay đổi kích thước chiều cao của chế độ xem tiêu đề dựa trên các nhãn bằng ví dụ này ( stackoverflow.com/questions/20982558/ trộm )
djibouti33

@ djibouti33 bạn có thể vui lòng cung cấp mã mẫu tối thiểu (ví dụ: ở định dạng của github repo) để tôi có thể dễ dàng kiểm tra vấn đề của bạn không?
Anton Matosov 04/05/2015

Cảm ơn @Anton. Thiết kế của chúng tôi đã chuyển từ UITableView sang UICollectionView và may mắn thay tôi không thấy hành vi này. Nếu tôi có thể lấy lịch sử git của mình để tạo một dự án mẫu nhỏ, tôi sẽ cho bạn biết.
djibouti33

Một vấn đề đối với tôi kể từ khi tôi bắt đầu chạy trên sim iOS 9 nhưng khi tôi thử nghiệm trên iOS 8 thì rắc rối bắt đầu. Tôi cần đặt chiều rộng tối đa bằng tay.
naz

17

Tôi chỉ chiến đấu với kịch bản chính xác này, nhưng với khá nhiều lượt xem cần thay đổi kích thước và di chuyển xuống khi cần thiết. Nó đang khiến tôi phát điên, nhưng cuối cùng tôi cũng hiểu ra.

Đây là chìa khóa: Trình tạo giao diện thích đưa ra các ràng buộc bổ sung khi bạn thêm và di chuyển các khung nhìn và bạn có thể không nhận thấy. Trong trường hợp của tôi, tôi có một góc nhìn xuống một nửa có một ràng buộc bổ sung quy định kích thước giữa nó và giám sát của nó, về cơ bản ghim nó vào điểm đó. Điều đó có nghĩa là không có gì ở trên nó có thể thay đổi kích thước lớn hơn bởi vì nó sẽ đi ngược lại với ràng buộc đó.

Một cách dễ dàng để biết nếu đây là trường hợp bằng cách cố gắng thay đổi kích thước nhãn bằng tay. IB có cho phép bạn phát triển nó không? Nếu có, các nhãn bên dưới di chuyển như bạn mong đợi? Hãy chắc chắn rằng bạn đã kiểm tra cả hai thứ này trước khi thay đổi kích thước để xem các ràng buộc của bạn sẽ di chuyển quan điểm của bạn như thế nào:

Menu IB

Nếu chế độ xem bị kẹt, hãy thực hiện theo các chế độ xem bên dưới chế độ xem và đảm bảo rằng một trong số chúng không có không gian trên cùng để hạn chế giám sát. Sau đó, chỉ cần đảm bảo số lượng tùy chọn dòng của bạn cho nhãn được đặt thành 0 và nó sẽ chăm sóc phần còn lại.


Đúng, sau rất nhiều lần chơi với nó, tôi đã có thể có được hiệu ứng tôi muốn. Bạn chỉ cần suy nghĩ rất kỹ về những hạn chế mà bạn muốn. Điều đó không giúp ích gì cho việc IB liên tục đưa ra những ràng buộc mà bạn không mong đợi.
James Harpe

5

Tôi thấy bạn cần những điều sau đây:

  • Một hạn chế hàng đầu
  • Một ràng buộc hàng đầu (ví dụ: bên trái)
  • Một ràng buộc dấu (ví dụ: bên phải)
  • Đặt mức độ ưu tiên ôm nội dung, ngang thành thấp, vì vậy nó sẽ lấp đầy khoảng trống đã cho nếu văn bản ngắn.
  • Đặt kháng nén nội dung, ngang thành thấp, vì vậy nó sẽ bao bọc thay vì cố gắng trở nên rộng hơn.
  • Đặt số lượng dòng thành 0.
  • Đặt chế độ ngắt dòng thành gói từ.

Điều này sẽ làm việc trong xcode9. Tôi không phải làm bất cứ điều gì với ràng buộc về chiều cao nhãn (tôi không có gì): nó chỉ hoạt động ngoài hộp một khi nhãn sẽ bị hạn chế (theo dõi, dẫn đầu, trên và dưới). uikit làm phần còn lại
Anton Tropashko

Các ưu tiên ôm nội dung là vấn đề của tôi. Cảm ơn bạn đã cho tôi biết về tài sản đó cũng như khả năng chống nén. Bạn đã giúp tôi giải quyết một vấn đề kéo dài hàng giờ.
David Gay

0

Không có giải pháp nào khác được tìm thấy trong nhiều chủ đề về chủ đề này hoạt động hoàn hảo cho trường hợp của tôi (x nhãn đa dòng động trong các ô xem bảng động).

Tôi tìm thấy một cách để làm điều đó:

Sau khi đã đặt các ràng buộc trên nhãn của bạn và đặt thuộc tính đa dòng của nó thành 0, hãy tạo một lớp con của UILabel; Tôi đã gọi cho tôi AutoLayoutLabel:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end

0

Tôi có một UITableViewCell có nhãn bọc văn bản. Tôi làm việc gói văn bản như sau.

1) Đặt các ràng buộc UILabel như sau.

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

2) Đặt số của dòng đến 0.

3) Đã thêm ràng buộc chiều cao UILabel vào UITableViewCell.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) Trên UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5

-12

Một cách để làm điều này ... Khi tăng độ dài văn bản, hãy cố gắng thay đổi (giảm) phông chữ của văn bản nhãn bằng cách sử dụng

Label.adjustsFontSizeToFitWidth = YES;

1
Tôi muốn các phiên bản khác nhau của trình điều khiển chế độ xem có giao diện nhất quán, vì vậy tôi không muốn thay đổi kích thước phông chữ.
James Harpe
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.