Sắp xếp theo chiều dọc văn bản lên trên cùng trong một UILabel


2175

Tôi có một UILabelkhông gian cho hai dòng văn bản. Đôi khi, khi văn bản quá ngắn, văn bản này được hiển thị ở trung tâm dọc của nhãn.

Làm thế nào để tôi sắp xếp theo chiều dọc của văn bản để luôn luôn đứng đầu UILabel?

hình ảnh đại diện cho một UILabel với văn bản tập trung theo chiều dọc

Câu trả lời:


2702

Không có cách nào để đặt căn chỉnh dọc trên a UILabel, nhưng bạn có thể có được hiệu ứng tương tự bằng cách thay đổi khung của nhãn. Tôi đã làm cho nhãn của mình màu cam để bạn có thể thấy rõ những gì đang xảy ra.

Đây là cách nhanh chóng và dễ dàng để làm điều này:

    [myLabel sizeToFit];

sizeToFit để ép nhãn


Nếu bạn có nhãn có văn bản dài hơn sẽ tạo nhiều hơn một dòng, được đặt numberOfLinesthành 0(không ở đây có nghĩa là không giới hạn số dòng).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Văn bản nhãn dài hơn với sizeToFit


Phiên bản dài hơn

Tôi sẽ tạo nhãn của tôi bằng mã để bạn có thể thấy những gì đang diễn ra. Bạn cũng có thể thiết lập hầu hết điều này trong Trình tạo giao diện. Thiết lập của tôi là Ứng dụng dựa trên chế độ xem với hình nền tôi tạo bằng Photoshop để hiển thị lề (20 điểm). Nhãn có màu cam hấp dẫn để bạn có thể thấy những gì đang diễn ra với kích thước.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 20 point top and left margin. Sized to leave 20 pt at right.
    CGRect labelFrame = CGRectMake(20, 20, 280, 150);
    UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
    [myLabel setBackgroundColor:[UIColor orangeColor]];

    NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
    [myLabel setText:labelText];

    // Tell the label to use an unlimited number of lines
    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    [self.view addSubview:myLabel];
}

Một số hạn chế của việc sử dụng sizeToFitđi kèm với văn bản căn giữa hoặc phải. Đây là những gì xảy ra:

    // myLabel.textAlignment = NSTextAlignmentRight;
    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

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

Nhãn vẫn có kích thước với một góc trên cùng bên trái cố định. Bạn có thể lưu chiều rộng của nhãn gốc trong một biến và đặt nó sau sizeToFithoặc đặt chiều rộng cố định để khắc phục các vấn đề này:

    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    CGRect myFrame = myLabel.frame;
    // Resize the frame's width to 280 (320 - margins)
    // width could also be myOriginalLabelFrame.size.width
    myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
    myLabel.frame = myFrame;

liên kết nhãn


Lưu ý rằng sizeToFitsẽ tôn trọng chiều rộng tối thiểu của nhãn ban đầu của bạn. Nếu bạn bắt đầu với một nhãn rộng 100 và gọi sizeToFitnó, nó sẽ trả lại cho bạn một nhãn (có thể rất cao) với chiều rộng 100 (hoặc ít hơn một chút). Bạn có thể muốn đặt nhãn của mình thành chiều rộng tối thiểu bạn muốn trước khi thay đổi kích thước.

Căn chỉnh nhãn chính xác bằng cách thay đổi kích thước chiều rộng khung

Một số điều khác cần lưu ý:

Việc lineBreakModecó được tôn trọng hay không tùy thuộc vào cách thiết lập. NSLineBreakByTruncatingTail(mặc định) được bỏ qua sau sizeToFit, cũng như hai chế độ cắt ngắn khác (đầu và giữa). NSLineBreakByClippingcũng bị bỏ qua. NSLineBreakByCharWrappinghoạt động như bình thường. Chiều rộng khung hình vẫn được thu hẹp để phù hợp với chữ cái ngoài cùng bên phải.


Mark Amery đã đưa ra bản sửa lỗi cho NIB và Storyboards bằng Auto Layout trong các bình luận:

Nếu nhãn của bạn được bao gồm trong một ngòi hoặc bảng phân cảnh dưới dạng một khung nhìn phụ viewcủa ViewContoder sử dụng tính năng tự động thanh toán, thì sizeToFitcuộc gọi của bạn viewDidLoadsẽ không hoạt động, bởi vì kích thước tự động và vị trí của các cuộc phỏng vấn sau viewDidLoadsẽ được gọi và sẽ ngay lập tức hoàn tác các hiệu ứng của bạn sizeToFitgọi. Tuy nhiên, gọi sizeToFittừ bên trong viewDidLayoutSubviews sẽ làm việc.


Câu trả lời gốc của tôi (cho hậu thế / tài liệu tham khảo):

Điều này sử dụng NSStringphương pháp sizeWithFont:constrainedToSize:lineBreakMode:để tính chiều cao khung cần thiết để khớp với một chuỗi, sau đó đặt gốc và chiều rộng.

Thay đổi kích thước khung cho nhãn bằng văn bản bạn muốn chèn. Bằng cách đó bạn có thể chứa bất kỳ số lượng dòng.

CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont 
        constrainedToSize:maximumSize 
        lineBreakMode:self.dateLabel.lineBreakMode];

CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);

self.dateLabel.frame = dateFrame;

10
bạn cần xóa autolayout
hungbm06

4
Đây là một cách đơn giản để giải quyết vấn đề: stackoverflow.com/a/26632490/636559
AboulEinein

Nếu bạn sử dụng bố cục và bảng phân cảnh tự động, việc thêm một ràng buộc với tùy chọn "Xóa tại thời điểm xây dựng" sẽ được kiểm tra
JK ABC

Nếu bạn cần điều này hoạt động với adjustsFontSizeToFitWidththì hãy sử dụng sizeToFit, sau đó đặt khung của nhãn thành 0, 0, theWidthYouWant, nhãn.frame.size.height (là chiều cao mới được xác định bởi sizeToFit) THEN áp dụngadjustsFontSizeToFitWidth
Albert Renshaw

3
Câu trả lời này phức tạp không cần thiết và nó đang sử dụng một "từ xung quanh". Vui lòng xem đề xuất bên dưới chỉ đơn giản là thay đổi ưu tiên ôm nội dung dọc. Không yêu cầu bất kỳ mã nào ...
beetree

335
  1. Đặt văn bản mới:

    myLabel.text = @"Some Text"
  2. Đặt các maximum numberdòng thành 0 (tự động):

    myLabel.numberOfLines = 0
  3. Đặt khung của nhãn thành kích thước tối đa:

    myLabel.frame = CGRectMake(20,20,200,800)
  4. Gọi sizeToFitđể giảm kích thước khung hình để nội dung vừa vặn:

    [myLabel sizeToFit]

Khung nhãn bây giờ chỉ cao và đủ rộng để phù hợp với văn bản của bạn. Phía trên bên trái nên không thay đổi. Tôi đã thử nghiệm điều này chỉ với văn bản liên kết bên trái trên cùng. Đối với các sắp xếp khác, bạn có thể phải sửa đổi khung sau đó.

Ngoài ra, nhãn của tôi có kích hoạt gói từ.


Này Ben, tôi chỉ nhìn lại mã cũ của mình và cập nhật câu trả lời của mình với các bước chính xác cần thiết.
Jakob Egger

Điều này làm việc tốt cho tôi. Tôi đặt kích thước của UILabel của mình và thay đổi numberOfLines thành 0 trong IB và sau đó sau khi đặt văn bản có tên [myLabel sizeToFit].
Dan Ellis

hoạt động hoàn hảo đối với tôi, sau khi đặt số lượng dòng trong Attr. Thanh tra
d2burke

Không hoạt động trong trường hợp số lượng dòng nhiều hơn 1
Tom

Nó không hoạt động khi bạn muốn một nhãn gồm hai dòng, nhưng văn bản yêu cầu nhiều dòng hơn.
Jose Manuel Abarca Rodríguez

159

Đề cập đến giải pháp mở rộng:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

nên được thay thế bởi

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

Cần thêm không gian trong mỗi dòng mới được thêm vào, bởi vì UILabelslợi nhuận vận chuyển kéo dài của iPhone dường như bị bỏ qua :(

Tương tự, alignBottom cũng nên được cập nhật @" \n@%"thay cho "\n@%"(để khởi tạo chu kỳ phải được thay thế bằng "for (int i = 0 ...").

Phần mở rộng sau đây hoạt động với tôi:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

Sau đó gọi [yourLabel alignTop];hoặc [yourLabel alignBottom];sau mỗi lần gán văn bản của bạn.


@DS Tôi nhận thấy rằng bạn đang thêm VerticalAligngiữa dấu ngoặc đơn sau @implementation UILabel. Là người mới đối với Objective-C Tôi chưa từng chạy qua cú pháp này trước đây. Cái này gọi là gì?
Julian

Thật tuyệt vời, không biết về các danh mục, điều này mang lại cho tôi sự đánh giá cao hơn nữa đối với ngôn ngữ Objective-c. Học nhiều ngôn ngữ là rất quan trọng để trở thành một lập trình viên giỏi.
JeroenEijkhof

Đã đưa ra một upvote. nhưng tôi sẽ không hoạt động nếu bạn không biết số dòng là nhược điểm
Tjirp

Tôi phải hiển thị 3 dòng văn bản và căn chỉnh văn bản lên trên cùng. Vì vậy, tôi có nên đặt số dòng thành 3. Khi tôi đặt nó thành 3, tôi sẽ thấy "..." nếu văn bản ít hơn (phù hợp với một dòng). Làm thế nào để tránh điều này "..."
Satyam

1
Tôi đã đăng một bản chỉnh sửa của thể loại này, hy vọng nó sẽ sớm được phê duyệt. Các phương thức sizeWithFont:constrainedToSize:lineBreakMode:và sizeWithFont: đều bị khấu hao trong iOS7. Ngoài ra, danh mục này chỉ hoạt động trên nhãn khi numberOfLines lớn hơn 0.
timgcarlson

146

Chỉ trong trường hợp có bất kỳ sự giúp đỡ nào cho bất kỳ ai, tôi cũng gặp vấn đề tương tự nhưng có thể giải quyết vấn đề chỉ bằng cách chuyển từ sử dụng UILabelsang sử dụng UITextView. Tôi đánh giá cao điều này không dành cho tất cả mọi người vì chức năng hơi khác một chút.

Nếu bạn chuyển sang sử dụng UITextView, bạn có thể tắt tất cả các thuộc tính Chế độ xem cuộn cũng như Kích hoạt tương tác người dùng ... Điều này sẽ buộc nó hoạt động giống như một nhãn.

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


1
Không chắc chắn điều này sẽ ảnh hưởng đến hiệu suất như thế nào nếu nhiều UILabels được chuyển đổi thành chế độ xem văn bản.
ninjaneer

2
Tất cả các giải pháp khác trong chuỗi này không hoạt động với tôi trong iOS 7 (vì bất kỳ lý do gì). Nhưng chỉ cần sử dụng một UITextViewđã cho tôi kết quả mong muốn ngay lập tức.
Clifton Labrum

1
Đó là một cách giải quyết, nó vẫn cần một số điều chỉnh để làm cho nó trông thật hơn, nhưng thực sự đây là giải pháp không có mã đơn giản nhất mà tôi thấy, giơ ngón tay cái lên.
Itai Spector

1
Tôi thích giải pháp này. Cấp, có thể có vấn đề về hiệu suất và như vậy, đối với một nhãn đơn giản trên một chế độ xem tương đối đơn giản, điều này là hoàn hảo cho những gì tôi cần (và tôi không thể nhận thấy bất kỳ tác động nào về hiệu suất)
JCocking8

1
Một nhược điểm nhỏ của phương pháp này là nó sẽ giới thiệu thêm phần đệm nội tại cho văn bản. Một sửa chữa nhanh chóng là để giới thiệu một hạn chế tiêu cực.
Sira Lam

122

Không ồn ào, không ồn ào

@interface MFTopAlignedLabel : UILabel

@end


@implementation MFTopAlignedLabel

- (void)drawTextInRect:(CGRect) rect
{
    NSAttributedString *attributedText = [[NSAttributedString alloc]     initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
    rect.size.height = [attributedText boundingRectWithSize:rect.size
                                            options:NSStringDrawingUsesLineFragmentOrigin
                                            context:nil].size.height;
    if (self.numberOfLines != 0) {
        rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
    }
    [super drawTextInRect:rect];
}

@end

Không ồn ào, không khách quan-c, không ồn ào nhưng Swift 3:

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

Swift 4.2

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

Phiên bản nhanh chóng làm việc cho tôi mà không có bất kỳ tác dụng phụ! Công việc tuyệt vời
l.vasilev

2
Có lẽ câu trả lời tốt nhất ở đây, hoạt động trong tất cả các kịch bản. sizeToFit không hoạt động nếu nhãn nằm trong UITableviewCell. Làm tốt lắm.
rajat chauhan

79

Giống như câu trả lời ở trên, nhưng nó không hoàn toàn đúng, hoặc dễ dàng đưa vào mã để tôi dọn dẹp nó một chút. Thêm tiện ích mở rộng này vào tệp .h và .m của chính nó hoặc chỉ cần dán ngay phía trên triển khai bạn định sử dụng:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i<= newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@" \n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
    }
}
@end

Và sau đó để sử dụng, hãy đặt văn bản của bạn vào nhãn và sau đó gọi phương thức thích hợp để căn chỉnh nó:

[myLabel alignTop];

hoặc là

[myLabel alignBottom];

sizeWithFont không dùng nữa
tdios

68

Một cách thậm chí nhanh hơn (và bẩn hơn) để thực hiện điều này là bằng cách đặt chế độ ngắt dòng của UILabel thành "Clip" và thêm một số dòng mới cố định.

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

Giải pháp này sẽ không hiệu quả với tất cả mọi người - đặc biệt, nếu bạn vẫn muốn hiển thị "..." ở cuối chuỗi nếu vượt quá số dòng bạn đang hiển thị, bạn sẽ cần sử dụng một trong những các đoạn mã dài hơn - nhưng trong nhiều trường hợp, điều này sẽ giúp bạn có được thứ bạn cần.


3
Đặt chế độ ngắt dòng thành 'clip' dường như làm rối loạn việc tự động định cỡ nhãn. Sử dụng UILineBreakModeWordWrapthay thế.
Niels van der Rest

và tốt hơn là thêm không gian "\ n \ n"
djdance

68

Cách tiếp cận dễ nhất bằng Storyboard:

Nhúng nhãn trong StackView và đặt theo hai thuộc tính của StackView trong Trình theo dõi thuộc tính:

1- Axisđến Horizontal,

2 AlignmentđếnTop

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


1
Để có kết quả tốt hơn, bạn có thể thực hiện điều này StackView> View> UILabel, bởi vì khi bạn chỉ cần nhúng một UILabel bên trong StackView, StackView thay đổi kích thước để phù hợp với UILabel với kích thước tối thiểu
Daniel Beltrami

Ý tưởng tuyệt vời để đặt UILabelvào một số UIViewlớp con ( UIViewthường là đủ) và để cho nhãn đó phát triển theo hướng xuống. Cảm ơn!
Viktor Kucera

1
Tuyệt vời! Điều đáng nói là bạn cần phải xóa các ràng buộc trên UILabelvà để StackView thực hiện công việc của mình. Cảm ơn!
Luiz Dias

Với lệnh Editor-> Embed menu với nhãn của bạn được chọn, các ràng buộc nhãn sẽ được xóa cho bạn bằng Xcode, sau đó bạn có thể chỉ cần đặt các ràng buộc cho StackView. Cách tiếp cận này gần nhất với cách tiếp cận bố cục 'SwiftUI', đó là cách tôi phát hiện ra nó.
Rocket Garden

tại sao điều này làm việc
Novellizator

60

Thay vì UILabelbạn có thể sử dụng UITextFieldcó tùy chọn căn chỉnh dọc:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction

7
Hãy cẩn thận: UITextField chỉ cho phép một dòng văn bản.
David James

2
Để hoàn thành bình luận @DavidJames: UITextView sẽ phù hợp hơn
CedricSoubrie

49

Tôi đã vật lộn với điều này trong một thời gian dài và tôi muốn chia sẻ giải pháp của mình.

Điều này sẽ cung cấp cho bạn một UILabelvăn bản sẽ tự động thu nhỏ văn bản xuống 0,5 tỷ lệ và căn giữa văn bản theo chiều dọc. Các tùy chọn này cũng có sẵn trong Storyboard / IB.

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];

Nó hoạt động như hoàn hảo trong số tất cả các câu trả lời được cung cấp. Cảm ơn @David Greco. Cùng với các thuộc tính này, nếu chúng ta đặt điều chỉnhFontSizeToFitWidth thành CÓ thì văn bản sẽ vừa với khung mà không sửa đổi khung của nhãn.
Ashok

43

Tạo một lớp mới

NhãnTopAlign

tập tin .h

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

tập tin .m

#import "KwLabelTopAlign.h"


@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect {
    int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
    if(rect.size.height >= lineHeight) {
        int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
        int yMax = textHeight;
        if (self.numberOfLines > 0) {
            yMax = MIN(lineHeight*self.numberOfLines, yMax);    
        }

        [super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
    }
}

@end

Biên tập

Đây là một cách thực hiện đơn giản hơn, thực hiện tương tự:

#import "KwLabelTopAlign.h"

@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect
{
    CGFloat height = [self.text sizeWithFont:self.font
                            constrainedToSize:rect.size
                                lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    [super drawTextInRect:rect];
}

@end

+1 cho câu trả lời thực sự. Không giống như các sizeToFitgiải pháp, điều này thực sự làm cho việc UILabelđặt bất kỳ văn bản nào lên hàng đầu, ngay cả khi bạn tự động thay thế một văn bản ngắn hơn bằng một văn bản dài hơn hoặc ngược lại.
SnakE

38

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

Trong Trình tạo giao diện

  • Đặt UILabelkích thước của Văn bản lớn nhất có thể
  • Đặt Linesthành '0' trong Trình theo dõi thuộc tính

Trong mã của bạn

  • Đặt văn bản của nhãn
  • Gọi sizeToFitvào nhãn của bạn

Đoạn mã:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];

hoạt động rất tốt, ngoại trừ trong trường hợp của tôi, tôi cần đặt dòng thành 2 - có UILabel bên trong UITableViewCell và đặt thành 0 làm cho nó trùng nhau, nhưng cài đặt thành 2 hoạt động (ô có đủ chỗ cho 2 dòng)
eselk

34

Đối với Giao diện người dùng thích ứng (iOS8 trở lên), Sắp xếp theo chiều dọc của UILabel sẽ được đặt từ StoryBoard bằng cách thay đổi các thuộc tính noOfLines= 0` và

Những ràng buộc

  1. Điều chỉnh UILabel LefMargin, RightMargin và các ràng buộc ký quỹ hàng đầu.

  2. Thay đổi Content Compression Resistance Priority For Vertical= 1000` Vì vậy mà dọc> ngang.

Các ràng buộc của UILabel

Đã chỉnh sửa:

noOfLines=0

và các ràng buộc sau đây là đủ để đạt được kết quả mong muốn.

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


Nó thật là tuyệt vời. Bạn có thể giải thích tại sao dọc> ngang làm công việc không? Cảm ơn.
Gabriel

33

Tạo một lớp con của UILabel. Hoạt động như một lá bùa:

// TopLeftLabel.h

#import <Foundation/Foundation.h>

@interface TopLeftLabel : UILabel 
{
}

@end

// TopLeftLabel.m

#import "TopLeftLabel.h"

@implementation TopLeftLabel

- (id)initWithFrame:(CGRect)frame 
{
    return [super initWithFrame:frame];
}

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines 
{
    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];    
    textRect.origin.y = bounds.origin.y;
    return textRect;
}

-(void)drawTextInRect:(CGRect)requestedRect 
{
    CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:actualRect];
}

@end

Như đã thảo luận ở đây .


27

Tôi đã viết một chức năng để đạt được mục đích này. Bạn có thể xem:

// điều chỉnh chiều cao của nhãn nhiều dòng để làm cho nó thẳng hàng với đỉnh
+ (void) alignLabelWithTop: (UILabel *) nhãn {
  CGSize maxSize = CGSizeMake (nhãn.frame.size. Thong, 999);
  nhãn.adjowersFontSizeToFitWidth = NO;

  // lấy chiều cao thực tế
  CGSize factSize = [nhãn.text sizeWithFont: nhãn.font ràng buộcToSize: maxSize lineBreakMode: nhãn.lineBreakMode];
  CGRect orth = nhãn.frame;
  orth.size.height = factSize.height;
  nhãn.frame = orth;
}

Làm thế nào để sử dụng? (Nếu lblHello được tạo bởi Trình xây dựng giao diện, vì vậy tôi bỏ qua một số chi tiết thuộc tính UILabel)

lblHello.text = @ "Xin chào thế giới! Xin chào thế giới! Xin chào thế giới! Xin chào thế giới! Xin chào thế giới! Xin chào thế giới! Xin chào thế giới! Xin chào thế giới!";
lblHello.numberOfLines = 5;
[Sử dụng alignLabelWithTop: lblHello];

Tôi cũng đã viết nó trên blog của mình dưới dạng một bài viết: http://fstoke.me/blog/?p=2819


27

Tôi đã mất một lúc để đọc mã, cũng như mã trong trang được giới thiệu và thấy rằng tất cả họ đều cố gắng sửa đổi kích thước khung của nhãn, để căn chỉnh dọc trung tâm mặc định sẽ không xuất hiện.

Tuy nhiên, trong một số trường hợp, chúng tôi muốn nhãn chiếm hết tất cả các khoảng trắng đó, ngay cả khi nhãn có quá nhiều văn bản (ví dụ: nhiều hàng có chiều cao bằng nhau).

Ở đây, tôi đã sử dụng một cách khác để giải quyết nó, bằng cách đơn giản là điền các dòng mới vào cuối nhãn (xin lưu ý rằng tôi thực sự được thừa hưởng UILabel, nhưng nó không cần thiết):

CGSize fontSize = [self.text sizeWithFont:self.font];

finalHeight = fontSize.height * self.numberOfLines;
finalWidth = size.width;    //expected width of label

CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];

int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

for(int i = 0; i < newLinesToPad; i++)
{
    self.text = [self.text stringByAppendingString:@"\n "];
}

22

Những gì tôi đã làm trong ứng dụng của mình là đặt thuộc tính dòng của UILabel thành 0 cũng như tạo ràng buộc dưới cùng của UILabel và đảm bảo rằng nó đang được đặt thành> = 0 như trong hình bên dưới. nhập mô tả hình ảnh ở đây


19

Tôi đã lấy các đề xuất ở đây và tạo ra một khung nhìn có thể bao bọc một UILabel và sẽ kích thước nó và đặt số lượng dòng sao cho nó được căn chỉnh hàng đầu. Đơn giản chỉ cần đặt một UILabel làm một cuộc phỏng vấn:

@interface TopAlignedLabelContainer : UIView
{
}

@end

@implementation TopAlignedLabelContainer

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;

    for (UILabel *label in [self subviews])
    {
        if ([label isKindOfClass:[UILabel class]])
        {
            CGSize fontSize = [label.text sizeWithFont:label.font];

            CGSize textSize = [label.text sizeWithFont:label.font
                                     constrainedToSize:bounds.size
                                         lineBreakMode:label.lineBreakMode];

            label.numberOfLines = textSize.height / fontSize.height;

            label.frame = CGRectMake(0, 0, textSize.width,
                 fontSize.height * label.numberOfLines);
        }
    }
}

@end

19

Bạn có thể sử dụng TTTAttributionLabel , nó hỗ trợ căn chỉnh dọc.

@property (nonatomic) TTTAttributedLabel* label;
<...>

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;

16

Tôi đã tìm thấy câu trả lời cho câu hỏi này hiện đã hơi lỗi thời, vì vậy, thêm câu hỏi này cho người hâm mộ bố trí tự động ngoài kia.

Bố trí tự động làm cho vấn đề này khá nhỏ. Giả sử chúng ta thêm nhãn vào UIView *view, đoạn mã sau sẽ thực hiện điều này:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];

[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];

Chiều cao của nhãn sẽ được tính toán tự động (sử dụng nó intrinsicContentSize) và nhãn sẽ được đặt theo chiều ngang từ trên xuống theo chiều ngang, ở trên cùng của view.


15

Tôi đã sử dụng rất nhiều phương pháp ở trên và chỉ muốn thêm một cách tiếp cận nhanh và bẩn mà tôi đã sử dụng:

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];

Đảm bảo số lượng dòng mới trong chuỗi sẽ khiến bất kỳ văn bản nào lấp đầy không gian dọc có sẵn và đặt UILabel để cắt bớt bất kỳ văn bản tràn nào.

Bởi vì đôi khi đủ tốtđủ tốt .


Tuy nhiên, do sự thay đổi về chiều cao kích thước màn hình của thiết bị iOS, do đó, cần phải có một số lượng '\ n' khác nhau để tính đến chiều cao thay đổi của uilabel (đó là một khả năng). Do đó phương pháp này không đặc biệt hữu ích lâu dài.
Rambatino

Lưu ý: "nhanh và bẩn" không phải là "giải pháp hoàn hảo cho mọi thời đại". Chỉ cần nói.
Mã Roadie

2
@CodeRoadie Nhanh và bẩn đã lừa tôi, tôi có một vài vấn đề về bố cục với câu trả lời thực sự. Tôi có thể làm điều đó "đúng cách", nhưng cảm ơn bạn đã tiết kiệm thời gian cho tôi!
Séraphin Hochart

@dGambit xin lưu ý: "nhanh và bẩn "
Code Roadie

1
Một cái gì đó tôi đã học gần đây khi tải động các chế độ xem với UITextViewnó là nó có thể gọi dlopenđể hỗ trợ nhập văn bản. Điều này có thể gây ra độ trễ lớn trên luồng UI, vì vậy cách tiếp cận này hiệu quả hơn nhiều!
yano

14

Tôi muốn có một nhãn có thể có nhiều dòng, cỡ chữ tối thiểu và được căn giữa cả theo chiều ngang và chiều dọc trong chế độ xem chính. Tôi đã thêm nhãn của mình theo chương trình vào quan điểm của mình:

- (void) customInit {
    // Setup label
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.label.numberOfLines = 0;
    self.label.lineBreakMode = UILineBreakModeWordWrap;
    self.label.textAlignment = UITextAlignmentCenter;

    // Add the label as a subview
    self.autoresizesSubviews = YES;
    [self addSubview:self.label];
}

Và sau đó khi tôi muốn thay đổi văn bản của nhãn của mình ...

- (void) updateDisplay:(NSString *)text {
    if (![text isEqualToString:self.label.text]) {
        // Calculate the font size to use (save to label's font)
        CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
        self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
        CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
            self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
            textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        }
        // In cases where the frame is still too large (when we're exceeding minimum font size),
        // use the views size
        if (textSize.height > self.frame.size.height) {
            textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
        }

        // Draw 
        self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
        self.label.text = text;
    }
    [self setNeedsDisplay];
}

Mong rằng sẽ giúp được ai đó!


14

FXLabel (trên github) thực hiện việc này ngoài hộp bằng cách đặt label.contentModethành UIViewContentModeTop. Thành phần này không phải do tôi tạo ra, nhưng nó là thành phần tôi sử dụng thường xuyên và có hàng tấn tính năng, và dường như hoạt động tốt.


11

đối với bất kỳ ai đọc điều này bởi vì văn bản bên trong nhãn của bạn không được căn giữa theo chiều dọc, hãy nhớ rằng một số loại phông chữ không được thiết kế như nhau. ví dụ: nếu bạn tạo nhãn có kích thước zapfino 16, bạn sẽ thấy văn bản không được căn giữa hoàn hảo theo chiều dọc.

tuy nhiên, làm việc với helvetica sẽ tập trung vào văn bản của bạn theo chiều dọc.


Nhiều phông chữ tùy chỉnh không phải là trung tâm dọc. UILabel hoặc UITextView luôn được căn giữa theo chiều dọc. Không cần phải suy nghĩ về sự liên kết dọc trong lập trình iOS.
Amit Singh

11

Sử dụng textRect(forBounds:limitedToNumberOfLines:).

class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
    }
}

Thưa ngài là một vị thần!
Diogo Antunes

1
Câu trả lời này sẽ nhận được nhiều cách nâng cao hơn vì đây là giải pháp tốt nhất và sạch nhất!
Michael Ochs

10

Phân lớp UILabel và hạn chế hình chữ nhật vẽ, như thế này:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];
    rect.size.height = MIN(rect.size.height, sizeThatFits.height);

    [super drawTextInRect:rect];
}

Tôi đã thử giải pháp liên quan đến phần đệm dòng mới và gặp phải hành vi không chính xác trong một số trường hợp. Theo kinh nghiệm của tôi, việc hạn chế bản vẽ như trên sẽ dễ dàng hơn so với lộn xộn numberOfLines.

PS Bạn có thể tưởng tượng dễ dàng hỗ trợ UIViewContentMode theo cách này:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];

    if (self.contentMode == UIViewContentModeTop) {
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }
    else if (self.contentMode == UIViewContentModeBottom) {
        rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }

    [super drawTextInRect:rect];
}

10

Nếu bạn đang sử dụng tính năng tự động thanh toán, hãy đặt nội dung dọcHuggingP Warriority thành 1000, bằng mã hoặc IB. Trong IB, bạn có thể phải xóa giới hạn chiều cao bằng cách đặt mức ưu tiên thành 1 và sau đó xóa nó.


8

Miễn là bạn không làm bất kỳ nhiệm vụ phức tạp nào, bạn có thể sử dụng UITextViewthay vìUILabels .

Vô hiệu hóa cuộn.

Nếu bạn muốn văn bản được hiển thị hoàn toàn chỉ cần người dùng sizeToFitsizeThatFits:phương thức


8

Nhanh chóng

let myLabel : UILabel!

Để làm cho văn bản Nhãn của bạn vừa với màn hình và nó ở trên cùng

myLabel.sizeToFit()

Để làm cho phông chữ của nhãn của bạn vừa với chiều rộng của màn hình hoặc kích thước chiều rộng cụ thể.

myLabel.adjustsFontSizeToFitWidth = YES

và một số văn bản Sắp xếp cho nhãn:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified


Chỉ cần thay đổi cú pháp từ cú pháp cũ của [myLabel sizeToFit]. Cảm ơn bạn!
velkoon

7

Đây là một giải pháp cũ, hãy sử dụng tính năng tự động thanh toán trên iOS> = 6

Giải pháp của tôi:

  1. Tự chia dòng (bỏ qua cài đặt bọc nhãn)
  2. Tự vẽ đường thẳng (bỏ qua căn chỉnh nhãn)

@interface UITopAlignedLabel : UILabel

@end

@implementation UITopAlignedLabel

#pragma mark Instance methods

- (NSArray*)splitTextToLines:(NSUInteger)maxLines {
    float width = self.frame.size.width;

    NSArray* words = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSMutableArray* lines = [NSMutableArray array];

    NSMutableString* buffer = [NSMutableString string];    
    NSMutableString* currentLine = [NSMutableString string];

    for (NSString* word in words) {
        if ([buffer length] > 0) {
            [buffer appendString:@" "];
        }

        [buffer appendString:word];

        if (maxLines > 0 && [lines count] == maxLines - 1) {
            [currentLine setString:buffer];
            continue;
        }

        float bufferWidth = [buffer sizeWithFont:self.font].width;

        if (bufferWidth < width) {
            [currentLine setString:buffer];
        }
        else {
            [lines addObject:[NSString stringWithString:currentLine]];

            [buffer setString:word];
            [currentLine setString:buffer];
        }
    }

    if ([currentLine length] > 0) {
        [lines addObject:[NSString stringWithString:currentLine]];
    }

    return lines;
}

- (void)drawRect:(CGRect)rect {
    if ([self.text length] == 0) {
        return;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, self.textColor.CGColor);
    CGContextSetShadowWithColor(context, self.shadowOffset, 0.0f, self.shadowColor.CGColor);

    NSArray* lines = [self splitTextToLines:self.numberOfLines];
    NSUInteger numLines = [lines count];

    CGSize size = self.frame.size;
    CGPoint origin = CGPointMake(0.0f, 0.0f);

    for (NSUInteger i = 0; i < numLines; i++) {
        NSString* line = [lines objectAtIndex:i];

        if (i == numLines - 1) {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeTailTruncation];            
        }
        else {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeClip];
        }

        origin.y += self.font.lineHeight;

        if (origin.y >= size.height) {
            return;
        }
    }
}

@end
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.