UILabel no encoge automáticamente el texto para que se ajuste al tamaño de la etiqueta

119

Tengo esta extraña cuestión, y trato im con él durante más de 8 horas ahora .. Dependiendo de la situación que tengo que calcular UILabelsel tamaño dinámicamente,
por ejemplo,
mi UIViewControllerrecibe un evento y el cambio i UILabelstamaño. de mayor a menor. El tamaño de mi se UILabelhace más pequeño y obtengo el tamaño correcto necesario, pero el texto en mi UILabelpermanece igual, el mismo tamaño de fuente, etc. Necesito que la fuente sea más pequeña, para que todo el texto se ajuste a UILabel. Entonces, la pregunta es cómo hacer que el texto se ajuste a mi etiqueta autoshrinkingo algo así.

En mi xib, UILabels autoshrinkestá marcado, también el número de líneas se establece en 0, y también mi cadena tiene nuevos símbolos de línea (\ n), y he seleccionado el modo de salto de línea a wordwrap. ¿Quizás alguien estaba en la misma situación que yo ahora y podría ayudarme? Realmente lo agradecería.

¡Gracias por adelantado!

EDITAR: UILabel el tamaño de fuente mínimo se establece en 10

Lukas
fuente
¿Cuál es el tamaño mínimo de su fuente para la etiqueta que establezca?
AJPatel

Respuestas:

159

En caso de que todavía esté buscando una solución mejor, creo que esto es lo que quiere:

Un valor booleano que indica si el tamaño de la fuente debe reducirse para que la cadena del título encaje en el rectángulo delimitador de la etiqueta (esta propiedad solo es efectiva cuando la numberOfLinespropiedad se establece en 1).

Al establecer esta propiedad, minimumScaleFactorDEBE establecerse también (un buen valor predeterminado es 0.5).

Rápido

var adjustsFontSizeToFitWidth: Bool { get set }

C objetivo

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;

Un valor booleano que indica si el espaciado entre letras debe ajustarse para que se ajuste a la cadena dentro del rectángulo de límites de la etiqueta.

Rápido

var allowsDefaultTighteningForTruncation: Bool { get set }

C objetivo

@property(nonatomic) BOOL allowsDefaultTighteningForTruncation;

Fuente .

lester
fuente
18
Como nota al margen, minimumFontSizeestá obsoleto en iOS 6.0. Úselo en su minimumScaleFactorlugar.
lester
14
Sí, la contracción automática no funciona para varias líneas en UILabel. Intente imaginar esto: tiene texto con varias líneas, desea reducirlo para que "encaje" con el ancho. Entonces, ¿debería encoger todo el texto para que quepa en una línea, o las palabras deben permanecer en la misma línea y encogerse para ajustarse a cada ancho? Este último es el caso más común, pero no olvide que las palabras también están configuradas para organizarse en varias líneas. Incluso si la organización automática del texto está deshabilitada, tendrá que enfrentarse con cada línea del texto con un tamaño de fuente diferente, ya que no todas las palabras se ajustarán al ancho.
lester
2
Creo que esta respuesta con una categoría aquí es bastante buena, incluso podría ser lo que ha implementado de todos modos. Definitivamente, esto es algo que falta en la API de Apple, o tal vez simplemente no ven que la reducción debería ser un caso de uso común para varias líneas de texto estático .
lester
1
bueno, sí, ese es un buen punto, pero de todos modos, creo que si establezco el número de líneas en 0, esa es una declaración clara de que podría haber una o más líneas. Y el encogimiento automático podría determinarse por los números de línea, supongo ... Pero de todos modos, gracias por aclarar las cosas. Pensé que estaba haciendo algo mal. Una categoría es una buena idea, supongo que voy a hacer eso en otro proyecto donde lo necesitaré. Aprecio su ayuda, buena suerte;)
Lukas
4
@lester Debe encogerse para que todo el texto sea visible en el número de líneas declaradas para la etiqueta dadas sus dimensiones actuales. No es necesario intentar hacer que cada línea tenga un tamaño diferente. Estoy realmente sorprendido de que no pueda resolver esto. Así que si tengo una (potencialmente) larga cadena a mostrar lo que puedo o bien tener múltiples líneas o lo han automóvil de tamaño, pero no ambos. Eso es adorable.
devios1
125

Así es como obtengo el Autoshrinktrabajo de UILabel (especialmente para la altura de la fuente de la etiqueta que se ajusta en el dispositivo 4s desde 6s Plus Storyboard) en iOS 9.2, Xcode 7.2 ...

ingrese la descripción de la imagen aquí

  • El número de líneas es 0
  • Saltos de línea: Clip
  • Autoencogimiento: Escala de fuente mínima 0,25
Oh ho
fuente
15
Estos son los 3 ingredientes necesarios para que una etiqueta se encoja realmente, me faltaba la configuración de salto de línea del clip. Además, si está adyacente a otras etiquetas (que también pueden encogerse automáticamente), entonces se deben establecer prioridades de compresión / abrazo o se deben dar restricciones explícitas de ancho o alto. Esta debería ser la respuesta actualmente aceptada.
Korey Hinton
3
¡Número de líneas lo hizo por mí! Gracias
Michael
Asegúrese de que su etiqueta tenga todas las restricciones, especialmente al principio y al final.
Mashhadi
2
Probé con las mismas opciones en Xcode8 y encontré que no funcionaba. Por favor, ayúdenme si alguien tiene la idea de esto.
Ganesh
75

minimumFontSize está en desuso en iOS 6.

Así que usa en minimumScaleFactorlugar de minmimumFontSize.

lbl.adjustsFontSizeToFitWidth = YES
lbl.minimumScaleFactor = 0.5

Rápido 5

lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
SwiftiSwift
fuente
Bien respondido. Resolvió mi problema. Gracias
Abdul Yasin
1
@AntonMatosov, no, ¡no es así!
Iulian Onofrei
2
Sí, lo hace (ahora), si también establece los saltos de línea en Truncate Tail en lugar de Word Wrap ...
TheEye
21

también mi solución es la etiqueta booleana.adjustsFontSizeToFitWidth = YES; PERO. Debe en el Builder de la interfaz el cambio de Word Wrapping a " CLIP ". Luego, encoja automáticamente las etiquetas. Esto es muy importante.

loki-e
fuente
3
Solo cuando cambié de "Word Wrap" a "Clip", Autoshrink funcionó para mí.
NicJ
Cuando cambié el ajuste de palabras a un clip, pude cambiar el tamaño de una etiqueta con cero líneas. Chico, sería bueno si esto estuviera documentado.
DesignatedNerd
12

En Swift 3 (programáticamente) tuve que hacer esto:

let lbl = UILabel()
lbl.numberOfLines = 0
lbl.lineBreakMode = .byClipping
lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
lbl.font = UIFont.systemFont(ofSize: 15)
Naloiko Eugene
fuente
5

Puedes escribir como

UILabel *reviews = [[UILabel alloc]initWithFrame:CGRectMake(14, 13,270,30)];//Set frame
reviews.numberOfLines=0;
reviews.textAlignment = UITextAlignmentLeft;
reviews.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:12];
reviews.textColor=[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.8]; 
reviews.backgroundColor=[UIColor clearColor];

Puedes calcular el número de líneas así

CGSize maxlblSize = CGSizeMake(270,9999);
CGSize totalSize = [reviews.text sizeWithFont:reviews.font 
              constrainedToSize:maxlblSize lineBreakMode:reviews.lineBreakMode];

CGRect newFrame =reviews.frame;
newFrame.size.height = totalSize.height;
reviews.frame = newFrame;

CGFloat reviewlblheight = totalSize.height;

int lines=reviewlblheight/12;//12 is the font size of label

UILabel *lbl=[[UILabel alloc]init];
lbl.frame=CGRectMake(140,220 , 100, 25);//set frame as your requirement
lbl.font=[UIFont fontWithName:@"Arial" size:20];
[lbl setAutoresizingMask:UIViewContentModeScaleAspectFill];
[lbl setLineBreakMode:UILineBreakModeClip];
lbl.adjustsFontSizeToFitWidth=YES;//This is main for shrinking font
lbl.text=@"HelloHelloHello";

Espero que esto te ayude :-) esperando tu respuesta

Birju
fuente
entonces, si establezco un número de líneas en mi etiqueta, ¿el texto se encogerá automáticamente?
Lukas
si su contenido está fuera de ancho, tomará la siguiente línea
Birju
he hecho lo que sugieres, pero no funciona, ¿por qué la cantidad de líneas me ayudaría?
Lukas
tienes razón, lo intenté, no es útil, pero encontré una solución para ti, hazlo así, mi próxima respuesta
Birju
lbl.adjustsFontSizeToFitWidth = SÍ; ¡Trabajó para mi!
Desarrollador
4

Bueno, al final no encontré mi respuesta. Y creo que el encogimiento automático no funciona para varias líneas. Terminé usando la sugerencia en este enlace: encogimiento automático en un UILabel con varias líneas

La solución es calcular la altura del texto a un ancho dado y si el texto es más grande, reducir el tamaño de la fuente y luego hacer lo mismo nuevamente hasta que la altura sea igual o menor que el tamaño necesario.

No entiendo por qué esto debería ser tan difícil de implementar. Si me falta algo, todos pueden corregirme :)

Lukas
fuente
De acuerdo con otras respuestas aquí, la clave que faltaba era que debía configurar el ajuste de palabras en "Clip". Es contrario a la intuición, pero es necesario para que un UILabel se encoja automáticamente de la forma que desee. Esto funciona con un UILabel de varias líneas.
Duncan Babbage
4

Esto es para Swift 3 con Xcode 8.2.1 (8C1002)

La mejor solución que he encontrado es establecer un ancho fijo en su Storyboard o IB en la etiqueta. Establezca sus restricciones con restricción a los márgenes. En su viewDidLoad agregue las siguientes líneas de código:

override func viewDidLoad() {
            super.viewDidLoad()

            label.numberOfLines = 1
            label.adjustsFontSizeToFitWidth = true
            label.minimumScaleFactor = 0.5
        }

restricciones de etiqueta al margen

restricciones de etiqueta de ancho fijo al margen

inspector de atributos

Esto funcionó de maravilla y no se desborda a una nueva línea y encoge el texto para que se ajuste al ancho de la etiqueta sin problemas extraños y funciona en Swift 3.

Rob Mcelvenny
fuente
4

Es una gran pregunta, porque parece que ahora sería parte de la UIKitfuncionalidad incorporada o un marco relacionado. Aquí hay un buen ejemplo visual de la pregunta:

Animación de cambio de tamaño de fuente

No hay una forma fácil de evitarlo, pero definitivamente es posible. Una forma de hacerlo es probar mediante programación diferentes tamaños de fuente hasta que encuentre una que se ajuste razonablemente cerca de los límites de la vista. Puede lograr esto con la boundingRect()función de NSStringo NSAttributedString. Por ejemplo:

let string = "This is a test"
let infiniteSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height:CGFloat.greatestFiniteMagnitude)
let size = string.boundingRect(with: infiniteSize, options: [], attributes: [.font: UIFont.systemFont(ofSize: avgSize)] context: nil).size

Puede hacer una búsqueda binaria para ser más eficiente que un enfoque completo de fuerza bruta. También hay algunas consideraciones que son un poco más complicadas, incluido el ajuste correcto de palabras y el rendimiento del almacenamiento en caché de fuentes de iOS, si está buscando algo realmente sólido.

Si solo le importa mostrar el texto en la pantalla de una manera fácil, he desarrollado una implementación sólida en Swift, que también estoy usando en una aplicación de producción. Es una UIViewsubclase con escalado de fuente automático y eficiente para cualquier texto de entrada, incluidas varias líneas. Para usarlo, simplemente haría algo como:

let view = AKTextView()
// Use a simple or fancy NSAttributedString
view.attributedText = .init(string: "Some text here")
// Add to the view hierarchy somewhere

¡Eso es! Puede encontrar la fuente completa aquí: https://github.com/FlickType/AccessibilityKit

¡Espero que esto ayude!

Kosta Eleftheriou
fuente
1
Noviembre de 2018: parece que FlickType y AccessibilityKit se han vuelto privados o se han eliminado.
Chris Paveglio
3

En iOS 9 solo tenía que:

  1. Agregue restricciones desde la izquierda y la derecha de la etiqueta a la supervista.
  2. Establezca el modo de salto de línea en recorte en IB.
  3. Establezca el número de líneas en 1 en IB.

Alguien recomendó establecer el número de líneas en 0, pero para mí esto solo hizo que la etiqueta pasara a varias líneas ...

Nick Yap
fuente
Esto funcionó para mí. Acababa de seleccionar ay UILabela UITextFielden una celda estática y hacía clic en "Resolver problemas de autodiseño" y "Agregar restricciones faltantes". Todo estaba alineado, pero Autoshrink necesitaba saber la distancia a la etiqueta, para la cual "Agregar restricciones faltantes" no agregó una restricción.
Adrian
2

Creo que puede escribir el código siguiente después de alloc init Label

UILabel* lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, 280, 50)];
lbl.text = @"vbdsbfdshfisdhfidshufidhsufhdsf dhdsfhdksbf hfsdh fksdfidsf sdfhsd fhdsf sdhfh sdifsdkf ksdhfkds fhdsf dsfkdsfkjdhsfkjdhskfjhsdk fdhsf ";
[lbl setMinimumFontSize:8.0];
[lbl setNumberOfLines:0];
[lbl setFont:[UIFont systemFontOfSize:10.0]];
lbl.lineBreakMode = UILineBreakModeWordWrap;
lbl.backgroundColor = [UIColor redColor];
[lbl sizeToFit];
[self.view addSubview:lbl];

Está funcionando bien conmigo Úselo

iDhaval
fuente
1
gracias, pero esto no calculará ni reducirá la fuente al mínimo necesario, según tengo entendido, y también ¿por qué su fuente mínima es más grande de lo normal?
Lukas
2

Dos años después, y este problema sigue circulando ...

En iOS 8 / XCode 6.1, a veces encontraba que mi UILabel(creado en unUITableViewCell , con AutoLayout activado y restricciones flexibles para que tuviera mucho espacio) no cambiaba de tamaño para ajustarse a la cadena de texto.

La solución, como en años anteriores, fue configurar el texto y luego llamar sizeToFit.

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    . . .
    cell.lblCreatedAt.text = [note getCreatedDateAsString];
    [cell.lblCreatedAt sizeToFit];
}

(Suspiro.)

Mike Gledhill
fuente
1

A continuación, le indicamos cómo hacerlo: suponga que la siguiente etiqueta de mensaje es la etiqueta que desea que tenga el efecto deseado. Ahora, pruebe estas simples líneas de códigos:

    //SET THE WIDTH CONSTRAINTS FOR LABEL.
    CGFloat constrainedWidth = 240.0f;//YOU CAN PUT YOUR DESIRED ONE,THE MAXIMUM WIDTH OF YOUR LABEL.
 //CALCULATE THE SPACE FOR THE TEXT SPECIFIED.
    CGSize sizeOfText=[yourText sizeWithFont:yourFont constrainedToSize:CGSizeMake(constrainedWidth, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];
    UILabel *messageLabel=[[UILabel alloc] initWithFrame:CGRectMake(20,20,constrainedWidth,sizeOfText.height)];
    messageLabel.text=yourText;
    messageLabel.numberOfLines=0;//JUST TO SUPPORT MULTILINING.
Anand
fuente
Hola, gracias por tu respuesta, pero no necesito calcular la altura de la etiqueta, tengo un tamaño fijo y, dependiendo de eso, mi fuente tiene que hacerse más pequeña si es necesario.
Lukas
1

no funciona si numberOfLines > 1 lo que hice provocó una condición como esta-

if(lblRecLocation.text.length > 100)
    lblRecLocation.font = [UIFont fontWithName:@"app_font_name" size:10];
Vaibhav Saran
fuente
0

Llegué tarde a la fiesta, pero como tenía el requisito adicional de tener una palabra por línea, esta adición funcionó para mí:

label.numberOfLines = [labelString componentsSeparatedByString:@" "].count;

Apple Docs dice:

Normalmente, el texto de la etiqueta se dibuja con la fuente que especifique en la propiedad de fuente. Sin embargo, si esta propiedad se establece en SÍ y el texto de la propiedad de texto excede el rectángulo delimitador de la etiqueta, el receptor comienza a reducir el tamaño de fuente hasta que la cadena se ajusta o se alcanza el tamaño mínimo de fuente. En iOS 6 y versiones anteriores, esta propiedad solo es efectiva cuando la propiedad numberOfLines se establece en 1.

Pero esto es una mentira. ¡Una mentira que te digo! Es cierto para todas las versiones de iOS. Específicamente, esto es cierto cuando se usa un UILabeldentro de un UICollectionViewCellpara el cual el tamaño está determinado por restricciones ajustadas dinámicamente en tiempo de ejecución a través de un diseño personalizado (ej.self.menuCollectionViewLayout.itemSize = size ).

Entonces, cuando se usa junto con adjustsFontSizeToFitWidthy minimumScaleFactor, como se mencionó en respuestas anteriores, la configuración programática numberOfLinesbasada en el recuento de palabras resolvió el problema de reducción automática. Hacer algo similar basado en el recuento de palabras o incluso de caracteres puede producir una solución "lo suficientemente cercana".

Justin Whitney
fuente
0

En Swift 4 (mediante programación):

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200.0, height: 200.0))
label.adjustsFontSizeToFitWidth = true
label.numberOfLines = 0

label.text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."

view.addSubview(label)
Hadži Lazar Pešić
fuente
0

Swift 4, Xcode 9.4.1

La solución que funcionó para mí: tenía una etiqueta dentro de una celda de vista de colección y el texto de la etiqueta se estaba recortando. Establezca los atributos como se muestra a continuación en Storyboard

Lines = 0
LineBreak = Word Wrap
Set yourlabel's leading and trailing constraint = 0 (using Autolayout)
Naishta
fuente