UILabel não reduz o texto automaticamente para caber no tamanho do rótulo

119

Eu tenho esse problema estranho, e estou lidando com ele há mais de 8 horas. Dependendo da situação, eu tenho que calcular o UILabelstamanho dinamicamente,
por exemplo ,
meu UIViewControllerrecebe um evento e eu mudo o UILabelstamanho. de maior para menor. O tamanho do meu UILabelfica menor e eu obtenho o tamanho correto necessário, mas o texto no meu UILabelpermanece o mesmo, o mesmo tamanho de fonte etc. Eu preciso que a fonte diminua, para que o texto inteiro caiba no UILabel. Então a questão é como fazer o texto caber na minha etiqueta autoshrinkingou algo assim?

No meu xib, UILabels autoshrinkestá marcado, também o número de linhas é definido como 0 e também minha string tem novos símbolos de linha (\ n) e selecionei o modo de quebra de linha para wordwrap. Talvez alguém estivesse na mesma situação que eu agora e pudesse me ajudar? Eu realmente iria apreciar isso.

Desde já, obrigado!

EDITAR: UILabel o tamanho mínimo da fonte é definido como 10

Lukas
fonte
qual é o tamanho mínimo de sua fonte para etiqueta que você definiu, por favor, adicione.
AJPatel

Respostas:

159

Caso você ainda esteja procurando uma solução melhor, acho que o que você quer:

Um valor booleano que indica se o tamanho da fonte deve ser reduzido para ajustar a string do título no retângulo delimitador do rótulo (esta propriedade é efetiva apenas quando a numberOfLinespropriedade é definida como 1).

Ao definir esta propriedade, minimumScaleFactorDEVE ser definido também (um bom padrão é 0,5).

Rápido

var adjustsFontSizeToFitWidth: Bool { get set }

Objective-C

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;

Um valor booleano que indica se o espaçamento entre as letras deve ser ajustado para caber na string dentro do retângulo de limites do rótulo.

Rápido

var allowsDefaultTighteningForTruncation: Bool { get set }

Objective-C

@property(nonatomic) BOOL allowsDefaultTighteningForTruncation;

Fonte .

Lester
fonte
18
Como uma nota lateral, minimumFontSizeestá obsoleto no iOS 6.0. Use em seu minimumScaleFactorlugar.
lester
14
Sim, a redução automática não funciona para várias linhas em UILabel. Tente imaginar o seguinte: você tem um texto com várias linhas, quer encolhê-lo para que "caiba" na largura. Portanto, ele deve encolher todo o texto para caber em uma linha ou as palavras devem ficar na mesma linha e encolher para caber em cada largura? Este último é o caso mais comum, mas não se esqueça de que as palavras também estão configuradas para se organizarem em várias linhas. Mesmo se a auto-organização do texto estiver desabilitada, você terá que encarar cada linha do texto com tamanhos de fonte diferentes, pois nem todas as palavras caberão na largura.
lester
2
Acho que essa resposta com uma categoria aqui é muito boa, pode até ser o que você implementou de qualquer maneira. Definitivamente, isso é algo que está faltando na API da Apple, ou talvez eles simplesmente não percebam que a redução deve ser um caso de uso comum para várias linhas de texto estático .
lester
1
bem, sim, é um bom ponto, mas de qualquer maneira, acho que se eu definir o número de linhas como 0, isso é uma declaração clara de que pode haver uma ou mais linhas. E a redução automática pode ser determinada pelos números das linhas, eu acho ... Mas de qualquer maneira, obrigado por esclarecer as coisas. Eu pensei que estava fazendo algo errado. Uma categoria é uma boa ideia, acho que vou fazer isso em outro projeto onde vou precisar disso. Agradecemos sua ajuda, boa sorte;)
Lukas,
4
@lester Deve encolher para que todo o texto fique visível no número de linhas declarado para o rótulo, dadas as suas dimensões atuais. Não é necessário tentar fazer com que cada linha tenha um tamanho diferente. Estou realmente surpreso que ele não consiga descobrir isso. Então, se eu tiver uma (potencialmente) longa seqüência para mostrar que eu posso quer ter várias linhas ou tê-lo auto-size, não ambos. Isso é adorável.
devios1
125

É assim que consigo o UILabel Autoshrinkfuncionar (especialmente para altura de ajuste da fonte do rótulo no dispositivo 4s do 6s Plus Storyboard) no iOS 9.2, Xcode 7.2 ...

insira a descrição da imagem aqui

  • O número de linhas é 0
  • Quebras de linha: clipe
  • Redução automática: Escala mínima da fonte 0,25
Oh Ho
fonte
15
Estes são os 3 ingredientes necessários para um rótulo realmente encolher, eu estava perdendo a configuração de quebra de linha do clipe. Além disso, se for adjacente a outros rótulos (que também podem ser reduzidos automaticamente), as prioridades de compressão / aperto precisam ser definidas ou restrições explícitas de largura ou altura devem ser fornecidas. Esta deve ser a resposta atualmente aceita.
Korey Hinton
3
Número de linhas fez isso por mim! Obrigado
Michael
Certifique-se de que sua etiqueta tenha todas as restrições, especialmente à esquerda e à direita.
Mashhadi de
2
Eu tentei com as mesmas opções no Xcode8 e não estava funcionando. Por favor me ajude se alguém tiver uma idéia sobre isso.
Ganesh
75

minimumFontSize está obsoleto no iOS 6.

Portanto, use em minimumScaleFactorvez de minmimumFontSize.

lbl.adjustsFontSizeToFitWidth = YES
lbl.minimumScaleFactor = 0.5

Swift 5

lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
SwiftiSwift
fonte
Bem respondido. Resolveu meu problema. Obrigado
Abdul Yasin,
1
@AntonMatosov, não, não faz!
Iulian Onofrei
2
Sim, é (agora) - se você também definir as quebras de linha para Truncate Tail em vez de Word Wrap ...
TheEye
21

também minha solução é o booleano label.adjustsFontSizeToFitWidth = YES; MAS. Você deve no construtor de interface a mudança de Word Wrapping para " CLIP ". Em seguida, reduza automaticamente os rótulos. Isto é muito importante.

loki-e
fonte
3
Somente quando mudei de "Word Wrap" para "Clip", o Autoshrink funcionou para mim.
NicJ
Quando mudei a quebra de linha para clipe, consegui redimensionar em uma etiqueta com zero linhas. Rapaz, seria bom se isso fosse documentado.
DesignatedNerd
12

No Swift 3 (programaticamente), tive que fazer isso:

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

Você pode escrever 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];

Você pode calcular o número de linhas assim

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 isso ajude você :-) aguardando sua resposta

Birju
fonte
portanto, se definir o número de linhas para meu rótulo, o texto será automaticamente reduzido?
Lukas
se o seu conteúdo está fora de largura, então vai demorar nextLine
Birju
hey eu fiz como você sugeriu, mas não funciona, por que o número de linhas me ajudaria?
Lukas
você está certo, eu tentei não é útil, mas achei a solução para você, assim, minha próxima resposta
Birju
lbl.adjustsFontSizeToFitWidth = YES; Funcionou para mim!
Desenvolvedor
4

Bem, no final eu não encontrei minha resposta. E acho que o autoshrink não funciona para várias linhas. Acabei usando a sugestão neste link: autoshrink em um UILabel com várias linhas

A solução é calcular a altura do texto na largura dada e se o texto for maior, diminuir o tamanho da fonte e fazer o mesmo novamente até que a altura seja igual ou menor que o tamanho necessário.

Não entendo por que isso deve ser tão difícil de implementar. Se eu estiver faltando alguma coisa, todos são bem-vindos para me corrigir :)

Lukas
fonte
De acordo com outras respostas aqui, a principal coisa que faltava era definir a quebra de linha como "Clipe". É contra-intuitivo, mas isso é necessário para que um UILabel encolha automaticamente da maneira que você deseja. Isso funciona com um UILabel de várias linhas.
Duncan Babbage de
4

Isso é para Swift 3 executando Xcode 8.2.1 (8C1002)

A melhor solução que encontrei é definir uma largura fixa em seu Storyboard ou IB na etiqueta. Defina suas restrições com restrição às margens. Em seu viewDidLoad, adicione as seguintes linhas de código:

override func viewDidLoad() {
            super.viewDidLoad()

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

rótulo restrições à margem

restrições de etiqueta de largura fixa à margem

inspetor de atributos

Isso funcionou perfeitamente e não transborda para uma nova linha e encolhe o texto para caber na largura da etiqueta sem problemas estranhos e funciona no Swift 3.

Rob Mcelvenny
fonte
4

É uma ótima pergunta, porque parece que isso já seria parte da UIKitfuncionalidade interna ou de uma estrutura relacionada. Aqui está um bom exemplo visual da pergunta:

Animação de redimensionamento de fonte

Não há maneira fácil de contornar isso, mas é definitivamente possível. Uma maneira de fazer isso é tentar de forma programática diferentes tamanhos de fonte até encontrar uma que se ajuste razoavelmente perto dos limites da visualização. Você pode fazer isso com a boundingRect()função de NSStringou NSAttributedString. Por exemplo:

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

Você pode fazer uma pesquisa binária para ser mais eficiente do que uma abordagem de força bruta completa. Existem também algumas considerações que são um pouco mais envolvidas, incluindo quebra de linha correta e desempenho de cache de fonte do iOS, se você estiver procurando por algo realmente robusto.

Se você só se preocupa em mostrar o texto na tela de maneira fácil, desenvolvi uma implementação robusta em Swift, que também estou usando em um aplicativo de produção. É uma UIViewsubclasse com dimensionamento de fonte eficiente e automático para qualquer texto de entrada, incluindo várias linhas. Para usá-lo, você simplesmente faria algo como:

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

É isso aí! Você pode encontrar a fonte completa aqui: https://github.com/FlickType/AccessibilityKit

Espero que isto ajude!

Kosta Eleftheriou
fonte
1
Novembro de 2018: aparece que o FlickType e o AccessibilityKit tornaram-se privados ou foram removidos.
Chris Paveglio
3

No iOS 9, eu só precisava:

  1. Adicione restrições à esquerda e à direita do rótulo para a supervisualização.
  2. Defina o modo de quebra de linha para recorte em IB.
  3. Defina o número de linhas para 1 em IB.

Alguém recomendou definir o número de linhas como 0, mas para mim isso apenas fez o rótulo ir para várias linhas ...

Nick Yap
fonte
Isso funcionou para mim. Eu tinha acabado de selecionar um UILabele um UITextFieldem uma célula estática e clicar em "Resolve AutoLayout Issues" e "Add Missing Constraints". Tudo estava alinhado, mas Autoshrink precisava saber a distância até o rótulo, para o qual "Adicionar restrições ausentes" não adicionou uma restrição.
Adrian de
2

Eu acho que você pode escrever o código abaixo depois de alocar 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 bem comigo Use-o

iDhaval
fonte
1
obrigado, mas isso não vai calcular ou reduzir a fonte ao mínimo necessário como eu entendo, e também por que sua fonte mínima é maior do que o normal?
Lukas
2

Dois anos depois, e esse problema ainda está por aí ...

No iOS 8 / XCode 6.1, às vezes percebia que meu UILabel(criado em a UITableViewCell, com AutoLayout ativado e restrições flexíveis para que tivesse muito espaço) não se redimensionava para caber na string de texto.

A solução, como nos anos anteriores, foi definir o texto e depois telefonar sizeToFit.

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

(Suspiro.)

Mike Gledhill
fonte
1

Veja como fazer isso. Suponha que a seguinte messageLabel seja o rótulo que você deseja que tenha o efeito desejado. Agora, tente estas linhas simples 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
fonte
Ei obrigado pela sua resposta, mas não preciso calcular a altura da etiqueta, fixei o tamanho e dependendo disso minha fonte terá que diminuir se necessário.
Lukas
1

não funciona se o numberOfLines > 1 que eu fiz fizesse uma condição como esta-

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

Chegando tarde à festa, mas como eu tinha o requisito adicional de ter uma palavra por linha, essa adição funcionou para mim:

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

Apple Docs diz:

Normalmente, o texto do rótulo é desenhado com a fonte especificada na propriedade da fonte. Se esta propriedade estiver definida como SIM, entretanto, e o texto na propriedade text exceder o retângulo delimitador do rótulo, o receptor começa a reduzir o tamanho da fonte até que a string se ajuste ou o tamanho mínimo da fonte seja alcançado. No iOS 6 e anteriores, esta propriedade é efetiva apenas quando a propriedade numberOfLines é definida como 1.

Mas isso é mentira. Uma mentira eu te digo! É verdade para todas as versões do iOS. Especificamente, isso é verdadeiro ao usar um UILabeldentro de um UICollectionViewCellpara o qual o tamanho é determinado por restrições ajustadas dinamicamente no tempo de execução por meio do layout personalizado (por exemplo self.menuCollectionViewLayout.itemSize = size).

Portanto, quando usado em conjunto com adjustsFontSizeToFitWidthe minimumScaleFactor, conforme mencionado nas respostas anteriores, a configuração programada com numberOfLinesbase na contagem de palavras resolveu o problema de redução automática. Fazer algo semelhante com base na contagem de palavras ou até mesmo na contagem de caracteres pode produzir uma solução "próxima o suficiente".

Justin Whitney
fonte
0

Em Swift 4 (programaticamente):

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ć
fonte
0

Swift 4, Xcode 9.4.1

A solução que funcionou para mim: eu tinha um rótulo dentro de uma célula de visualização de coleção e o texto do rótulo estava sendo cortado. Defina os atributos como abaixo no Storyboard

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