Vraag Lijn tekst verticaal uit in een UILabel


ik heb een UILabel met ruimte voor twee regels tekst. Soms, wanneer de tekst te kort is, wordt deze tekst weergegeven in het verticale midden van het label.

Hoe kan ik de tekst verticaal uitlijnen zodat deze altijd bovenaan staat UILabel?

image representing a UILabel with vertically-centered text


1984
2018-06-28 08:54


oorsprong


antwoorden:


Er is geen manier om de verticale uitlijning in te stellen op a UILabel, maar je kunt hetzelfde effect krijgen door het frame van het label te wijzigen. Ik heb mijn labels oranje gemaakt zodat je duidelijk kunt zien wat er gebeurt.

Dit is de snelle en eenvoudige manier om dit te doen:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Als u een label met langere tekst hebt dat meer dan één regel maakt, stel dan in numberOfLines naar 0 (nul betekent hier een onbeperkt aantal regels).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Langere versie

Ik maak mijn label in code zodat je kunt zien wat er aan de hand is. U kunt het grootste deel hiervan ook instellen in Interface Builder. Mijn setup is een View Based App met een achtergrondafbeelding die ik in Photoshop heb gemaakt om marges te laten zien (20 punten). Het label heeft een aantrekkelijke oranje kleur, zodat u kunt zien wat er met de afmetingen gebeurt.

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

Enkele beperkingen van het gebruik sizeToFit in het spel komen met in het midden of rechts uitgelijnde tekst. Dit is wat er gebeurt:

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

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

enter image description here

Het label heeft nog steeds de afmetingen met een vaste linkerbovenhoek. U kunt de breedte van het originele label in een variabele opslaan en vervolgens instellen sizeToFit, of geef het een vaste breedte om deze problemen tegen te gaan:

    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


Let daar op sizeToFit respecteert de minimale breedte van uw initiële label. Als u begint met een label 100 breed en belt sizeToFit daarop krijg je een (mogelijk zeer hoog) label terug met 100 (of een beetje minder) breedte. Misschien wilt u uw label instellen op de minimale breedte die u wilt voordat u het formaat wijzigt.

Correct label alignment by resizing the frame width

Een paar andere dingen om op te merken:

Of lineBreakMode wordt gerespecteerd, hangt af van hoe het is ingesteld. NSLineBreakByTruncatingTail (de standaardinstelling) wordt hierna genegeerd sizeToFit, evenals de andere twee truncatiemodi (hoofd en midden). NSLineBreakByClipping wordt ook genegeerd. NSLineBreakByCharWrapping werkt zoals gewoonlijk. De breedte van het frame is nog steeds versmald tot de meest rechtse letter.


Mark Amery gaf een correctie voor NIB's en storyboards met behulp van Auto Layout in de comments:

Als uw label is opgenomen in een punt of storyboard als een subweergave van de view van een ViewController die autolayout gebruikt en vervolgens de sizeToFit inbellen viewDidLoad zal niet werken, omdat autolayout de grootte en positie van de subvisies erna nahoudt viewDidLoad wordt gebeld en maakt onmiddellijk de gevolgen van uw ongedaan sizeToFit noemen. Echter, bellen sizeToFit van binnenuit viewDidLayoutSubviews  zullen werk.


Mijn oorspronkelijke antwoord (voor het nageslacht / referentie):

Dit gebruikt de NSString methode sizeWithFont:constrainedToSize:lineBreakMode: om de framehoogte te berekenen die nodig is om een ​​reeks te passen, stelt u vervolgens de oorsprong en breedte in.

Wijzig het formaat van het kader voor het label met behulp van de tekst die u wilt invoegen. Op die manier kunt u elk aantal regels aanpassen.

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;

2561
2018-06-28 10:36



  1. Stel de nieuwe tekst in:

    myLabel.text = @"Some Text"
    
  2. Stel de maximum number van lijnen naar 0 (automatisch):

    myLabel.numberOfLines = 0
    
  3. Zet het frame van het label op de maximale grootte:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. telefoontje sizeToFit om de framegrootte te verkleinen zodat de inhoud precies past:

    [myLabel sizeToFit]
    

Het labelskader is nu net hoog en breed genoeg om in uw tekst te passen. De linkerbovenhoek moet ongewijzigd blijven. Ik heb dit alleen getest met tekst die linksboven is uitgelijnd. Voor andere uitlijningen moet u mogelijk het kader naderhand wijzigen.

Bovendien is mijn label voorzien van woordomslag.


315
2017-08-27 16:24



Verwijzen naar de uitbreidingsoplossing:

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

moet worden vervangen door

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

Extra ruimte is nodig in elke toegevoegde nieuwe regel, omdat de iPhone UILabels'achterstand van koets lijkt te worden genegeerd :(

Evenzo moet alignBottom ook worden bijgewerkt met een @" \n@%" in plaats van "\n@%" (voor cyclusinitialisatie moet ook worden vervangen door "for (int i = 0 ...").

De volgende extensie werkt voor mij:

// -- 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

Bel dan [yourLabel alignTop]; of [yourLabel alignBottom]; na elke thyLabel-teksttoewijzing.


151
2017-09-09 13:01



Voor het geval dat het iemand van enig nut zou zijn, had ik hetzelfde probleem maar kon ik het probleem oplossen door eenvoudigweg over te schakelen van het gebruik van UILabel gebruiken UITextView. Ik waardeer dat dit niet voor iedereen is omdat de functionaliteit een beetje anders is.

Als u naar het gebruik overschakelt UITextView, kunt u alle eigenschappen van de bladerweergave en gebruikersinteractie ingeschakeld uitschakelen ... Hierdoor wordt het gedwongen om meer op een label te lijken.

enter image description here


126
2017-10-05 12:46



Geen mopperen, geen gedoe

@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

Geen muss, geen Objective-c, geen gedoe maar 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



Zoals het bovenstaande antwoord, maar het klopte niet helemaal, of het was makkelijk om in code te slaan, dus heb ik het een beetje opgeschoond. Voeg deze extensie toe aan zijn eigen .h- en .m-bestand of plak het direct boven de implementatie die u wilt gebruiken:

#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

En gebruik vervolgens uw tekst in het label en roep vervolgens de juiste methode om het uit te lijnen:

[myLabel alignTop];

of

[myLabel alignBottom];

76
2018-03-04 02:44



Een nog snellere (en vuilere) manier om dit te bereiken, is door de regelmodus van het UILabel in te stellen op "Clip" en een vast aantal nieuwe regels toe te voegen.

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

Deze oplossing werkt niet voor iedereen - met name als u nog steeds "..." aan het einde van uw reeks wilt weergeven als deze groter is dan het aantal regels dat u weergeeft, moet u een van de volgende regels gebruiken: de langere stukjes code - maar in veel gevallen krijgt u wat u nodig hebt.


66
2018-04-18 21:08



In plaats van UILabel je mag gebruiken UITextField met verticale uitlijnoptie:

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

56
2018-02-10 10:36



Ik heb hier lang mee geworsteld en ik wilde mijn oplossing delen.

Dit geeft je een UILabel dat zal tekst automatisch verkleinen tot 0,5 schalen en de tekst verticaal centreren. Deze opties zijn ook beschikbaar in Storyboard / IB.

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

47
2017-10-16 16:38