Tengo una 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 que esté siempre en la parte superior de la UILabel
?
No hay manera de establecer el alineamiento vertical en una UILabel
, pero puedes conseguir el mismo efecto cambiando el marco de la etiqueta. He hecho mis etiquetas de color naranja para que puedas ver claramente lo que está sucediendo.
Aquí está la manera rápida y fácil de hacer esto:
[myLabel sizeToFit];
Si tiene una etiqueta con un texto más largo que hará más de una línea, establezca numberOfLines
a 0
(cero aquí significa un número ilimitado de líneas).
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
Texto de etiqueta más largo con sizeToFit]2
Versión más larga
Voy a hacer mi etiqueta en el código para que pueda ver lo que está pasando. Usted puede configurar la mayor parte de esto en Interface Builder también. Mi configuración es una aplicación basada en la vista con una imagen de fondo que hice en Photoshop para mostrar los márgenes (20 puntos). La etiqueta es de un atractivo color naranja para que pueda ver lo que está pasando 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 el texto alineado al centro o a la derecha. Esto es lo que ocurre:
// myLabel.textAlignment = NSTextAlignmentRight;
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
introduzca la descripción de la imagen aquí
La etiqueta sigue teniendo un tamaño fijo en la esquina superior izquierda. Puede guardar el ancho de la etiqueta original en una variable y establecerlo después de sizeToFit
, o darle 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;
Ten en cuenta que sizeToFit
respetará el ancho mínimo de tu etiqueta inicial. Si empiezas con una etiqueta de 100 de ancho y llamas a sizeToFit
sobre ella, te devolverá una etiqueta (posiblemente muy alta) con 100 (o un poco menos) de ancho. Es posible que desee establecer su etiqueta a la anchura mínima que desea antes de cambiar el tamaño.
Corregir la alineación de la etiqueta redimensionando el ancho del marco]5
Algunas otras cosas a tener en cuenta:
El respeto de lineBreakMode
depende de su configuración. El modo NSLineBreakByTruncatingTail
(por defecto) se ignora después de sizeToFit
, al igual que los otros dos modos de truncamiento (cabeza y medio). También se ignora "NSLineBreakByClipping". El modo NSLineBreakByCharWrapping
funciona como siempre. El ancho del marco se sigue reduciendo para ajustarse a la letra más a la derecha.
Mark Amery]6 dio una solución para NIBs y Storyboards usando Auto Layout en los comentarios:
Si tu etiqueta está incluida en un nib o storyboard como una subvista de la
view
de un ViewController que utiliza autolayout, entonces poner tu llamadasizeToFit
enviewDidLoad
no funcionará, porque el autolayout dimensiona y posiciona las subvistas después de que se llame aviewDidLoad
y deshará inmediatamente los efectos de tu llamadasizeToFit
. Sin embargo, llamar asizeToFit
desde dentro deviewDidLayoutSubviews
funcionará.
Esto utiliza el método NSString
sizeWithFont:constrainedToSize:lineBreakMode:
para calcular la altura del marco necesaria para encajar una cadena, luego establece el origen y el ancho.
Redimensiona el marco para la etiqueta utilizando el texto que quieres insertar. De esta manera puedes 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;
Como la respuesta anterior, pero no era del todo correcto, o fácil de pegar en el código así que lo limpié un poco. Añade esta extensión a su propio archivo .h y .m o simplemente pégala justo encima de la implementación que vayas a utilizar:
#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 usarlo, pon tu texto en la etiqueta, y luego llama al método apropiado para alinearlo:
[myLabel alignTop];
o
[myLabel alignBottom];
Me tomé un tiempo para leer el código, así como el código en la página introducida, y encontré que todos ellos tratan de modificar el tamaño del marco de la etiqueta, por lo que la alineación vertical central por defecto no aparecería.
Sin embargo, en algunos casos sí queremos que la etiqueta ocupe todos esos espacios, aunque la etiqueta tenga tanto texto (por ejemplo, varias filas con igual altura).
En este caso, utilicé una forma alternativa de resolverlo, simplemente rellenando con nuevas líneas el final de la etiqueta (por favor, 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 "];
}