Вертикално подравняване на текста към горната част в UILabel

Имам UILabel с място за два реда текст. Понякога, когато текстът е твърде кратък, той се показва във вертикалния център на етикета.

Как да подравня вертикално текста, за да бъде винаги в горната част на UILabel?

Решение

Няма начин да се зададе вертикално подравняване на UILabel, но можете да постигнете същия ефект, като промените рамката на етикета. Направих моите етикети оранжеви, за да можете ясно да видите какво се случва.

Ето бързия и лесен начин да направите това:

    [myLabel sizeToFit];


Ако имате етикет с по-дълъг текст, който ще се състои от повече от един ред, задайте numberOfLines на 0 (нула тук означава неограничен брой редове).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];


Дълга версия

Ще направя етикета си в код, за да можете да видите какво'се случва. Можете да настроите повечето от това и в Interface Builder. Моята настройка е приложение, базирано на изглед, с фоново изображение, което направих във Photoshop, за да покажа полетата (20 точки). Етикетът е в атрактивен оранжев цвят, за да можете да видите какво'става с размерите.

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

Някои ограничения при използването на sizeToFit се проявяват при текст, подравнен в центъра или вдясно. Ето какво се случва:

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

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

Етикетът все още е оразмерен с фиксиран горен ляв ъгъл. Можете да запазите ширината на оригиналния етикет'в променлива и да я зададете след sizeToFit, или да му зададете фиксирана ширина, за да се справите с тези проблеми:

    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;


Обърнете внимание, че sizeToFit ще се съобрази с минималната ширина на вашия първоначален етикет'. Ако започнете с етикет с ширина 100 и извикате sizeToFit за него, той ще ви върне (вероятно много висок) етикет с ширина 100 (или малко по-малко). Може да искате да зададете минималната ширина на етикета, която искате, преди да промените размера.

Някои други неща за отбелязване:

Дали ще се спазва lineBreakMode зависи от начина, по който е зададен. NSLineBreakByTruncatingTail (по подразбиране) се игнорира след sizeToFit, както и другите два режима на съкращаване (head и middle). NSLineBreakByClipping също се игнорира. NSLineBreakByCharWrapping работи както обикновено. Широчината на рамката все още се стеснява, за да се побере в най-дясната буква.


Mark Amery даде поправка за NIB и Storyboards, използващи Auto Layout, в коментарите:

Ако вашият етикет е включен в ниб или сториборд като под-изглед на view на ViewController, който използва autolayout, тогава поставянето на вашето извикване на sizeToFit в viewDidLoad няма да сработи, защото autolayout оразмерява и позиционира под-изгледите след извикването на viewDidLoad и веднага ще отмени ефекта от вашето извикване на sizeToFit. Обаче извикването на sizeToFit от рамките на viewDidLayoutSubviews ще работи.


**Първоначалният ми отговор (за сведение/препоръка):**

Това използва метода NSString sizeWithFont:constrainedToSize:lineBreakMode:, за да изчисли височината на рамката, необходима за побиране на низ, след което задава началото и ширината.

Променете размера на рамката за етикета, като използвате текста, който искате да вмъкнете. По този начин можете да вместите произволен брой редове.

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;
Коментари (13)

Подобно на отговора по-горе, но той не беше съвсем правилен или лесен за въвеждане в кода, така че го изчистих малко. Добавете това разширение или към собствен .h и .m файл, или просто го поставете точно над имплементацията, която възнамерявате да използвате:


#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
Коментари (0)

Отделих известно време, за да прочета кода, както и кода във въведената страница, и установих, че всички те се опитват да променят размера на рамката на етикета, така че вертикалното подравняване по подразбиране да не се появи в центъра.

В някои случаи обаче искаме етикетът да заеме всички тези пространства, дори ако етикетът наистина има толкова много текст (например няколко реда с еднаква височина).

Тук използвах алтернативен начин за решаване, като просто подредих нови редове в края на етикета (pls note that I actually inherited the UILabel, but it is not necessary):

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 "];
}
Коментари (0)