Câu hỏi Sắp xếp văn bản theo chiều dọc lên trên trong nhãn UILabel


tôi có một UILabel với khô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 cách nào để căn chỉnh theo chiều dọc văn bản để luôn ở trên cùng của UILabel?

image representing a UILabel with vertically-centered text


1986
2018-06-28 08:54


gốc




Các câu trả lời:


Không có cách nào để đặt căn chỉnh dọc trên một 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 tôi 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 để thực hiện việc này:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


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, hãy đặt numberOfLines đến 0 (số không ở đây có nghĩa là số dòng không giới hạn).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


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

Tôi sẽ làm cho nhãn của tôi trong mã để bạn có thể xem những gì đang xảy 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à một ứng dụng dựa trên xem với một hình nền tôi đã thực hiện trong Photoshop để hiển thị lợi nhuận (20 điểm). Nhãn là màu cam hấp dẫn để bạn có thể thấy những gì đang xảy ra với các 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ế sử dụng sizeToFit đi vào chơi với văn bản trung tâm hoặc căn phải. Đây là những gì sẽ xảy ra:

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

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

enter image description here

Nhãn vẫn có kích thước với góc cố định trên cùng bên trái. 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 sizeToFit, hoặc cung cấp cho nó một chiều rộng cố định để chống lại những 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;

label alignment


Lưu ý rằng sizeToFit sẽ 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 sizeToFit trên đó, nó sẽ đưa bạn trở lại 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 ở chiều rộng tối thiểu bạn muốn trước khi thay đổi kích thước.

Correct label alignment by resizing the frame width

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

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


Đánh dấu Amery đã sửa lỗi cho NIB và Bảng phân cảnh bằng cách sử dụng Bố cục tự động trong nhận xét:

Nếu nhãn của bạn được bao gồm trong nib hoặc bảng phân cảnh dưới dạng phần phụ của view của một ViewController sử dụng autolayout, sau đó đặt sizeToFit gọi vào viewDidLoad sẽ không hoạt động, vì kích thước autolayout và vị trí các subviews sau viewDidLoad được gọi và sẽ ngay lập tức hoàn tác các tác động của sizeToFit gọi điện. Tuy nhiên, gọi điện sizeToFit từ bên trong viewDidLayoutSubviews  sẽ công việc.


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

Điều này sử dụng NSString phương pháp sizeWithFont:constrainedToSize:lineBreakMode: để tính chiều cao khung cần thiết để phù hợp với một chuỗi, sau đó đặt nguồn 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 các 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;

2563
2018-06-28 10:36



bạn cần xóa autolayout - hungbm06
Đâ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 tự động và bảng phân cảnh, việc thêm một ràng buộc với tùy chọn "Xóa tại thời gian xây dựng" được chọn sẽ giúp - JK ABC
Nếu bạn cần làm việc này với adjustsFontSizeToFitWidth sau đó sử dụng sizeToFit sau đó đặt khung của nhãn thành 0, 0, theWidthYouWant, label.frame.size.height (là chiều cao mới được xác định bởi sizeToFit) THEN áp dụng adjustsFontSizeToFitWidth - Albert Renshaw
Câu trả lời này là không cần thiết phức tạp và nó đang sử dụng một "từ xung quanh". Vui lòng xem gợi ý bên dưới chỉ đơn giản là thay đổi mức ưu tiên nội dung theo chiều dọc. Không yêu cầu bất kỳ mã nào ... - beetree


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

    myLabel.text = @"Some Text"
    
  2. Đặt maximum number của dòng đến 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 điện sizeToFit để giảm kích thước khung hình sao cho nội dung vừa vừa vặn:

    [myLabel sizeToFit]
    

Khung nhãn hiện chỉ cao và đủ rộng để vừa với văn bản của bạn. Phía trên cùng bên trái sẽ không thay đổi. Tôi đã thử nghiệm điều này chỉ với văn bản că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 đã bật gói từ.


315
2017-08-27 16:24



Hey Ben, tôi chỉ nhìn vào mã cũ của tôi một lần nữa, và cập nhật câu trả lời của tôi 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 và thay đổi numberOfLines thành 0 trong IB và sau đó sau khi đặt văn bản có tên là [myLabel sizeToFit]. - Dan Ellis
hoạt động hoàn hảo cho tôi, sau khi thiết lập số dòng trong Attr. Thanh tra - d2burke
Không hoạt động trong trường hợp số dòng nhiều hơn 1 - Tom
Nó không hoạt động khi bạn muốn một nhãn của hai dòng, nhưng văn bản đòi hỏi nhiều dòng hơn. - Jose Manuel Abarca Rodríguez


Tham khảo 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ằng

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

Không gian bổ sung là cần thiết trong mỗi dòng mới bổ sung, bởi vì iPhone UILabels'trailing vận chuyển trở lại dường như bị bỏ qua :(

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

Phần mở rộng sau hoạt động cho 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 là [yourLabel alignBottom]; sau mỗi lần gán văn bản trên nhãn của bạn.


151
2017-09-09 13:01



@ D.S. Tôi nhận thấy rằng bạn đang thêm VerticalAlign giữa dấu ngoặc đơn sau @implementation UILabel. Là mới đối với Objective-C Tôi đã không chạy qua cú pháp này trước đây. Cái này gọi là gì? - Julian
Tuyệt vời, không biết về các loại, đ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 thêm 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
Đã có một upvote. nhưng iirc điều này sẽ không hoạt động nếu bạn không biết số lượng các dòng đó là một nhược điểm - Tjirp
Tô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 đã đặt số dòng đến 3. Khi tôi đặt nó thành 3, tôi 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
Tôi có dòng thiết lập để 2 nhưng nó không làm cho sự khác biệt cho alignTop hoặc alignBottom, bất cứ điều gì tôi đang mất tích? label = [[UILabel alloc] init]; label.numberOfLines = 2; label.frame = CGRectMake (0, TABS_HEIGHT-25, self.frame.size.width, 25); label.font = [UIFont fontWithName: @ "Arial" size: 10]; label.textAlignment = UITextAlignmentCenter; [label alignTop]; - htafoya


Chỉ trong trường hợp đó là bất kỳ sự giúp đỡ cho bất cứ ai, tôi đã có cùng một vấn đề nhưng đã có thể giải quyết vấn đề chỉ đơn giản bằng cách chuyển từ sử dụng UILabel đối với việc sử dụng UITextView. Tôi đánh giá cao điều này không phải dành cho tất cả mọi người vì chức năng này 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 Scroll View cũng như User Interaction Enabled ... Điều này sẽ buộc nó hoạt động giống như một nhãn.

enter image description here


126
2017-10-05 12:46



Bạn 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
Tất cả các giải pháp khác về chủ đề này không hoạt động đối với tôi trong iOS 7 (vì bất kỳ lý do gì). Nhưng chỉ cần sử dụng UITextView đã cho tôi kết quả mong muốn ngay lập tức. - Clifton Labrum
Đó 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 xác thực, nhưng thực sự đây là giải pháp mã đơn giản nhất mà tôi đã thấy, không thích. - Itai Spector
Tôi thích giải pháp này. Cấp, có thể có vấn đề hiệu suất và như vậy, cho một nhãn đơn giản trên một cái nhìn 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 hiệu suất) - JCutting8
Một nhược điểm nhỏ của phương pháp này là nó sẽ giới thiệu thêm nội tại đệm vào văn bản. Sửa chữa nhanh là giới thiệu một ràng buộc tiêu cực. - Sira Lam


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 có Objective-c, không phiền phức 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)
    }

}

80
2018-05-21 07:47



Các 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ụ! Làm tốt lắm! - l.vasilev
Có lẽ câu trả lời hay nhất ở đây, hoạt động trong mọi tình huống. sizeToFit không hoạt động nếu nhãn nằm trong UITableviewCell. Làm tốt lắm. - rajat chauhan
Người đàn ông tuyệt vời - anoop4real


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 tát vào mã vì vậy tôi đã làm sạch nó lê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ỉ dán ngay phía trên triển khai mà bạn định sử dụng nó:

#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, đặ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];

76
2018-03-04 02:44



Bất cứ ai muốn thêm một phiên bản Swift 3 này? - Duncan Groenewald


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ố lượng cố định của dòng mới.

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

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


66
2018-04-18 21:08



Đặt chế độ ngắt dòng thành 'clip' có vẻ như làm hỏng kích thước tự động của nhãn. Sử dụng UILineBreakModeWordWrap thay thế. - Niels van der Rest
và thêm khoảng trống tốt hơn "\ n \ n" - djdance


Thay vì UILabel bạn có thể sử dụng UITextField có tùy chọn căn chỉnh theo chiều dọc:

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

56
2018-02-10 10:36



Caveat: UITextField chỉ cho phép một dòng văn bản. - David James
Để hoàn thành nhận xét @DavidJames: UITextView sẽ phù hợp hơn - CedricSoubrie


Tôi đã đấu tranh 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 UILabel sẽ tự động sửa văn bản xuống 0,5 vảy và căn giữa theo chiều dọc của văn bản. Các tùy chọn này cũng có sẵn trong Storyboard / IB.

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

47
2017-10-16 16:38



Nó hoạt động hoàn hảo trong 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 adjustsFontSizeToFitWidth thành YES thì văn bản sẽ vừa với khung mà không sửa đổi khung của nhãn. - Ashok Kumar S
Bạn có thể pl xây dựng? Tôi đã không nhận được cú pháp và cũng làm thế nào chúng ta có thể thiết lập giống nhau trong trình xây dựng ui kịch bản - Sasuke Uchiha


Tạo một lớp học mới

LabelTopAlign

.h tệp

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m tệp

#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

Chỉnh sửa

Dưới đây là triển khai đơ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

42
2017-08-04 08:07



1 cho câu trả lời thực sự. Không giống như sizeToFit các giải pháp này thực sự làm cho UILabel đặt bất kì văn bản ở trên cùng, ngay cả khi bạn tự động thay thế văn bản ngắn hơn bằng văn bản dài hơn hoặc ngược lại. - SnakE
tuyệt vời chỉ là những gì tôi cần.Có thể bạn hãy cho tôi biết làm thế nào để làm điều đó để dưới align văn bản. Cảm ơn bạn - Pratyusha Terli


enter image description here

Trong giao diện Builder

  • Bộ UILabel kích thước của văn bản lớn nhất có thể
  • Bộ Lines thành '0' trong Thanh tra thuộc tính

Trong mã của bạn

  • Đặt văn bản của nhãn
  • Gọi điện sizeToFit trên nhãn của bạn

Đoạn mã:

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

38
2018-01-03 04:40



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