Pregunta

Tengo un UILabel con espacio para dos líneas de texto.A veces, cuando el texto es demasiado corto, este texto se muestra en el centro vertical de la etiqueta.

¿Cómo puedo alinear verticalmente el texto para estar siempre en la parte superior de la UILabel?

image representing a UILabel with vertically-centered text

¿Fue útil?

Solución

No hay forma de establecer la alineación vertical en un UILabel, pero puede obtener el mismo efecto cambiando el marco de la etiqueta. Hice mis etiquetas de color naranja para que pueda ver claramente lo que está sucediendo.

Aquí está la manera rápida y fácil de hacer esto:

    [myLabel sizeToFit];

sizeToFit para exprimir una etiqueta


Si tiene una etiqueta con texto más largo que tendrá más de una línea, configure numberOfLines en 0 (cero aquí significa un número ilimitado de líneas).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Texto de etiqueta más largo con sizeToFit


Versión más larga

Haré mi etiqueta en el código para que pueda ver lo que está pasando. También puede configurar la mayor parte de esto en Interface Builder. Mi configuración es una aplicación basada en vista con una imagen de fondo que hice en Photoshop para mostrar márgenes (20 puntos). La etiqueta es de un atractivo color naranja para que pueda ver lo que sucede con las dimensiones.

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

Algunas limitaciones del uso de sizeToFit entran en juego con texto alineado al centro o a la derecha. Esto es lo que sucede:

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

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

ingrese la descripción de la imagen aquí

La etiqueta todavía tiene el tamaño con una esquina superior izquierda fija. Puede guardar el ancho de la etiqueta original en una variable y configurarlo después de lineBreakMode, o asignarle un ancho fijo para contrarrestar estos problemas:

    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;

alineación de etiquetas


Tenga en cuenta que NSLineBreakByTruncatingTail respetará el ancho mínimo de su etiqueta inicial. Si comienza con una etiqueta de 100 de ancho y llama a NSLineBreakByClipping, le devolverá una etiqueta (posiblemente muy alta) con 100 (o un poco menos) de ancho. Es posible que desee establecer su etiqueta al ancho mínimo que desea antes de cambiar el tamaño.

Corrija la alineación de la etiqueta cambiando el tamaño del ancho del marco

Algunas otras cosas a tener en cuenta:

Si se respeta NSLineBreakByCharWrapping depende de cómo se establezca. view (el valor predeterminado) se ignora después de viewDidLoad, al igual que los otros dos modos de truncamiento (head y middle). viewDidLayoutSubviews también se ignora. NSString funciona como siempre. El ancho del marco todavía se reduce para ajustarse a la letra más a la derecha.


Mark Amery dio una solución para NIBs y Storyboards usando Auto Layout en los comentarios:

  

Si su etiqueta se incluye en una plumilla o guión gráfico como una subvista de la sizeWithFont:constrainedToSize:lineBreakMode: de un ViewController que utiliza autolayout, entonces poner su <=> llamada en <=> no funcionará, porque los tamaños y posiciones de autolayout subvistas después de que se llame a <=> e inmediatamente deshacerá los efectos de su <=> llamada. Sin embargo, llamar a <=> desde <=> funcionará .


Mi respuesta original (para posteridad / referencia):

Esto utiliza el método <=> <=> para calcular la altura del marco necesaria para ajustar una cadena, luego establece el origen y el ancho.

Cambie el tamaño del marco para la etiqueta usando el texto que desea insertar. De esa manera puede acomodar cualquier número de líneas.

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;

Otros consejos

  1. Establezca el nuevo texto:

    myLabel.text = @"Some Text"
    
  2. Establezca el maximum number de líneas en 0 (automático):

    myLabel.numberOfLines = 0
    
  3. Establezca el marco de la etiqueta al tamaño máximo:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Llame a sizeToFit para reducir el tamaño del marco para que el contenido se ajuste:

    [myLabel sizeToFit]
    

El marco de las etiquetas ahora es lo suficientemente alto y ancho como para adaptarse a su texto. La parte superior izquierda no debe modificarse. He probado esto solo con texto alineado en la parte superior izquierda. Para otras alineaciones, es posible que deba modificar el marco posteriormente.

Además, mi etiqueta tiene habilitado el ajuste de texto.

Refiriéndose a la solución de extensión:

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

debe ser reemplazado por

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

Se necesita espacio adicional en cada nueva línea agregada, porque el iPhone UILabels 'retornos de carro final parece ignorarse :(

Del mismo modo, alignBottom también debe actualizarse con un @" \n@%" en lugar de "\n@%" (para la inicialización del ciclo debe reemplazarse por " for (int i = 0 ... " también) .

La siguiente extensión funciona para mí:

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

Luego llame al [yourLabel alignTop]; o [yourLabel alignBottom]; después de cada asignación de texto de su Etiqueta.

En caso de que sea de alguna ayuda para alguien, tuve el mismo problema pero pude resolver el problema simplemente cambiando de usar UILabel a UITextView. Aprecio que esto no sea para todos porque la funcionalidad es un poco diferente.

Si cambia a usar <=>, puede desactivar todas las propiedades de Vista de desplazamiento, así como la Interacción del usuario habilitada ... Esto lo obligará a actuar más como una etiqueta.

enter descripción de la imagen aquí

Sin muss, sin problemas

@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

Sin muss, sin Objective-c, sin problemas, pero 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)
    }

}

Al igual que la respuesta anterior, pero no era del todo correcto o fácil de introducir en el código, así que lo limpié un poco. Agregue esta extensión a su propio archivo .h y .m o simplemente péguelo justo encima de la implementación que desea usar:

#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

Y luego, para usar, coloque el texto en la etiqueta y luego llame al método apropiado para alinearlo:

[myLabel alignTop];

o

[myLabel alignBottom];

Una forma aún más rápida (y más sucia) de lograr esto es estableciendo el modo de salto de línea de UILabel en " Clip " y agregando una cantidad fija de saltos de línea.

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

Esta solución no funcionará para todos, en particular, si aún desea mostrar " ... " al final de su cadena si excede el número de líneas que está mostrando, necesitará usar uno de los bits de código más largos, pero en muchos casos esto le dará lo que necesita.

En lugar de UILabel puede usar UITextField que tiene la opción de alineación vertical:

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

He tenido problemas con este durante mucho tiempo y quería compartir mi solución.

Esto le dará un UILabel que reducirá automáticamente el texto a 0.5 escalas y centrará verticalmente el texto. Estas opciones también están disponibles en Storyboard / IB.

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

Guión solución: La más simple y sencilla es la de incorporar Label en StackView y la configuración de StackView del Axis a Horizontal, Alignment a Top en Attribute Inspector de Storyboard.

enter image description here

Crear una nueva clase

LabelTopAlign

.h archivo

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

archivo .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

Editar

Aquí hay una implementación más simple que hace lo mismo:

#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

ingrese la descripción de la imagen aquí

En el generador de interfaces

  • Establezca UILabel al tamaño del texto más grande posible
  • Establezca Lines en '0' en el Inspector de atributos

En tu código

  • Establecer el texto de la etiqueta
  • Llame sizeToFit en su etiqueta

Fragmento de código:

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

Para la IU adaptativa (iOS8 o posterior), la Alineación vertical de UILabel se configurará desde StoryBoard cambiando las propiedades  noOfLines = 0` y

  

Restricciones

     
      
  1. Ajuste de UILabel LefMargin, RightMargin y Top Margin Restrictions.

  2.   
  3. Cambiar Content Compression Resistance Priority For Vertical = 1000` Para que Vertical > Horizontal.

  4.   

 Restricciones de UILabel

Editado :

noOfLines=0

y las siguientes restricciones son suficientes para lograr los resultados deseados.

 ingrese la descripción de la imagen aquí

Crea una subclase de UILabel. Funciona como un encanto:

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

Como se discutió aquí .

Escribí una función util para lograr este propósito. Puedes echar un vistazo:

// adjust the height of a multi-line label to make it align vertical with top
+ (void) alignLabelWithTop:(UILabel *)label {
  CGSize maxSize = CGSizeMake(label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = NO;

  // get actual height
  CGSize actualSize = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode];
  CGRect rect = label.frame;
  rect.size.height = actualSize.height;
  label.frame = rect;
}

& # 65294; ¿Cómo usarlo? (Si lblHello es creado por el creador de interfaces, entonces omito algunos detalles de los atributos de UILabel)

lblHello.text = @"Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!";
lblHello.numberOfLines = 5;
[Utils alignLabelWithTop:lblHello];

También lo escribí en mi blog como un artículo: http://fstoke.me/blog/?p=2819

Me tomó un tiempo leer el código, así como el código en la página introducida, y descubrí que todos intentan modificar el tamaño del marco de la etiqueta, para que no aparezca la alineación vertical central predeterminada.

Sin embargo, en algunos casos queremos que la etiqueta ocupe todos esos espacios, incluso si la etiqueta tiene mucho texto (por ejemplo, varias filas con la misma altura).

Aquí, utilicé una forma alternativa de resolverlo, simplemente rellenando las nuevas líneas hasta el final de la etiqueta (tenga en cuenta que en realidad heredé el UILabel, pero no es necesario):

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

Tomé las sugerencias aquí y creé una vista que puede ajustar un UILabel y lo dimensionará y establecerá el número de líneas para que quede alineado en la parte superior. Simplemente ponga un UILabel como una subvista:

@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

Puede usar TTTAttributedLabel , es compatible con la alineación vertical.

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

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

He usado muchos de los métodos anteriores, y solo quiero agregar un enfoque rápido y sucio que he usado:

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

Asegúrese de que el número de líneas nuevas en la cadena hará que cualquier texto llene el espacio vertical disponible y configure UILabel para truncar cualquier texto que se desborde.

Porque a veces lo suficientemente bueno es lo suficientemente bueno .

Quería tener una etiqueta que pudiera tener líneas múltiples, un tamaño de fuente mínimo y centrada tanto horizontal como verticalmente en su vista principal. Agregué mi etiqueta mediante programación a mi vista:

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

Y luego, cuando quería cambiar el texto de mi etiqueta ...

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

¡Espero que ayude a alguien!

He encontrado que las respuestas a esta pregunta ahora están un poco desactualizadas, por lo que agrego esto para los fanáticos del diseño automático.

El diseño automático hace que este problema sea bastante trivial. Suponiendo que agreguemos la etiqueta a UIView *view, el siguiente código logrará esto:

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

La altura de la etiqueta se calculará automáticamente (usando su intrinsicContentSize) y la etiqueta se colocará de borde a borde horizontalmente, en la parte superior de view.

FXLabel (en github) hace esto fuera de la caja configurando label.contentMode a UIViewContentModeTop . Este componente no está hecho por mí, pero es un componente que uso con frecuencia y tiene toneladas de características, y parece funcionar bien.

Lo que hice en mi aplicación fue establecer la propiedad de línea de UILabel en 0, así como crear una restricción inferior de UILabel y asegurarme de que se establezca en > = 0 como se muestra en la imagen a continuación . ingrese la descripción de la imagen aquí

para cualquiera que lea esto porque el texto dentro de su etiqueta no está centrado verticalmente, tenga en cuenta que algunos tipos de fuente no están diseñados de la misma manera. por ejemplo, si crea una etiqueta con zapfino tamaño 16, verá que el texto no está perfectamente centrado verticalmente.

sin embargo, trabajar con helvetica centrará verticalmente su texto.

Subclase UILabel y restrinja el rectángulo de dibujo, así:

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

    [super drawTextInRect:rect];
}

Probé la solución que implica el relleno de nueva línea y encontré un comportamiento incorrecto en algunos casos. En mi experiencia, es más fácil restringir el dibujo de forma correcta que antes que meterse con numberOfLines.

P.S. Puede imaginarse fácilmente apoyando UIViewContentMode de esta manera:

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

Si está utilizando autolayout, establezca la ContentHuggingPriority vertical en 1000, ya sea en código o IB. En IB, puede que tenga que eliminar una restricción de altura estableciendo su prioridad en 1 y luego eliminándola.

Use textRect(forBounds:limitedToNumberOfLines:).

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

Mientras usted no está haciendo cualquier tarea compleja, puede utilizar UITextView en lugar de UILabels.

Desactivar el desplazamiento.

Si desea que el texto se mostrará completamente solo usuario sizeToFit y sizeThatFits: métodos

En rápido,

let myLabel : UILabel!

Para que el texto de su etiqueta se ajuste a la pantalla y esté en la parte superior

myLabel.sizeToFit()

Para que su fuente de etiqueta se ajuste al ancho de la pantalla o al ancho específico.

myLabel.adjustsFontSizeToFitWidth = YES

y algunos textAlignment para etiqueta:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

Esta es una solución antigua, use autolayout en iOS > = 6

Mi solución:
1 / Dividir líneas por mí mismo (ignorando la configuración de ajuste de etiqueta)
2 / Dibujar líneas por mí mismo (ignorando la alineación de la etiqueta)


@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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top