UILabel ne rétrécit pas automatiquement le texte pour s'adapter à la taille de l'étiquette

119

J'ai ce problème étrange, et je m'en occupe depuis plus de 8 heures maintenant. Selon la situation, je dois calculer la UILabelstaille de manière dynamique,
par exemple
mon UIViewControllerreçoit un événement et je change de UILabelstaille. du plus grand au plus petit. La taille de mon UILabeldevient plus petite et j'obtiens la bonne taille nécessaire, mais le texte de mon UILabelreste le même, la même taille de police, etc. J'ai besoin que la police devienne plus petite, pour que le texte entier corresponde au UILabel. La question est donc de savoir comment adapter le texte à mon étiquette autoshrinkingou quelque chose du genre?

Dans my xib, UILabels autoshrinkest coché, le nombre de lignes est également défini sur 0, et ma chaîne a également de nouveaux symboles de ligne (\ n), et j'ai sélectionné le mode de saut de ligne sur wordwrap. Peut-être que quelqu'un était dans la même situation que moi maintenant et pourrait m'aider? Ça me plairait vraiment.

Merci d'avance!

EDIT: UILabel la taille de police minimale est fixée à 10

Lukas
la source
quelle est la taille minimale de votre police pour l'étiquette que vous définissez, veuillez ajouter.
AJPatel

Réponses:

159

Dans le cas où vous cherchez toujours une meilleure solution, je pense que c'est ce que vous voulez:

Une valeur booléenne indiquant si la taille de la police doit être réduite afin d'adapter la chaîne de titre dans le rectangle englobant de l'étiquette (cette propriété n'est effective que lorsque la numberOfLinespropriété est définie sur 1).

Lors de la définition de cette propriété, minimumScaleFactorDOIT également être définie (une bonne valeur par défaut est 0,5).

Rapide

var adjustsFontSizeToFitWidth: Bool { get set }

Objectif c

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;

Une valeur booléenne indiquant si l'espacement entre les lettres doit être ajusté pour s'adapter à la chaîne dans le rectangle des limites de l'étiquette.

Rapide

var allowsDefaultTighteningForTruncation: Bool { get set }

Objectif c

@property(nonatomic) BOOL allowsDefaultTighteningForTruncation;

Source .

lester
la source
18
En passant, minimumFontSizeest obsolète dans iOS 6.0. Utilisez minimumScaleFactorplutôt.
lester
14
Oui, la réduction automatique ne fonctionne pas pour plusieurs lignes dans UILabel. Essayez d'imaginer ceci: vous avez du texte avec plusieurs lignes, vous voulez le réduire pour qu'il "corresponde" à la largeur. Alors devrait-il réduire le texte entier pour tenir sur une ligne, ou les mots rester dans la même ligne et rétrécir pour s'adapter à chaque largeur? Ce dernier est le cas le plus courant, mais n'oubliez pas que les mots sont également configurés pour s'organiser sur plusieurs lignes. Même si la disposition automatique du texte est désactivée, vous devrez faire face à chaque ligne du texte ayant une taille de police différente, car tous les mots ne correspondent pas à la largeur.
lester
2
Je pense que cette réponse avec une catégorie ici est assez bonne, c'est peut-être même ce que vous avez mis en œuvre de toute façon. C'est définitivement quelque chose qui manque dans l'API Apple, ou peut-être qu'ils ne voient tout simplement pas la réduction devrait être un cas d'utilisation courant pour plusieurs lignes de texte statique .
lester
1
eh bien oui c'est un bon point, mais de toute façon, je pense que si je fixe le nombre de lignes à 0, c'est une sorte d'énoncé clair qu'il pourrait y avoir une ou plusieurs lignes. Et l'auto-rétrécissement pourrait être dissuadé par les numéros de ligne, je suppose. Mais de toute façon, merci d'avoir effacé les choses. Je pensais que je faisais quelque chose de mal. Une catégorie est une bonne idée, je suppose que je vais le faire dans un autre projet où j'en aurai besoin. Appréciez votre aide, bonne chance;)
Lukas
4
@lester Il doit être réduit pour que tout le texte soit visible dans le nombre de lignes déclaré pour l'étiquette compte tenu de ses dimensions actuelles. Il n'est pas nécessaire d'essayer de donner à chaque ligne une taille différente. Je suis vraiment surpris qu'il ne puisse pas comprendre cela. Donc, si j'ai une chaîne (potentiellement) longue à afficher, je peux soit avoir plusieurs lignes, soit la redimensionner automatiquement, pas les deux. C'est adorable.
devios1
125

C'est ainsi que je fais Autoshrinkfonctionner UILabel (en particulier pour la hauteur de la police d'étiquette adaptée dans un appareil 4s à partir de 6s Plus Storyboard) dans iOS 9.2, Xcode 7.2 ...

entrez la description de l'image ici

  • Le nombre de lignes est égal à 0
  • Sauts de ligne: clip
  • Rétrécissement automatique: échelle de police minimale 0,25
ohho
la source
15
Ce sont les 3 ingrédients nécessaires pour qu'une étiquette rétrécisse réellement, il me manquait le paramètre de saut de ligne du clip. De plus, si elle est adjacente à d'autres étiquettes (qui peuvent également se rétrécir automatiquement), les priorités de compression / étreinte doivent être définies ou des contraintes de largeur ou de hauteur explicites doivent être données. Cela devrait être la réponse actuellement acceptée.
Korey Hinton
3
Le nombre de lignes l'a fait pour moi! Merci
Michael
Assurez-vous que votre étiquette a toutes les contraintes, en particulier les premières et les dernières.
Mashhadi
2
J'ai essayé avec les mêmes options dans Xcode8 et j'ai trouvé que cela ne fonctionnait pas. S'il vous plaît, aidez-moi si quelqu'un a une idée à ce sujet.
Ganesh
75

minimumFontSize est obsolète dans iOS 6.

Alors utilisez à la minimumScaleFactorplace de minmimumFontSize.

lbl.adjustsFontSizeToFitWidth = YES
lbl.minimumScaleFactor = 0.5

Swift 5

lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
SwiftiSwift
la source
Bien répondu. J'ai résolu mon problème. Merci
Abdul Yasin
1
@AntonMatosov, non, ce n'est pas le cas!
Iulian Onofrei
2
Oui, c'est le cas (maintenant) - si vous définissez également les sauts de ligne sur Truncate Tail au lieu de Word Wrap ...
TheEye
21

aussi ma solution est le label booléen.adjustsFontSizeToFitWidth = YES; MAIS. Vous devez dans l'interface Builder le commutateur Word Wrapping sur " CLIP ". Puis rétrécissez automatiquement les étiquettes. C'est très important.

loki-e
la source
3
Ce n'est que lorsque je suis passé de "Word Wrap" à "Clip" que la réduction automatique a fonctionné pour moi.
NicJ
Lorsque j'ai changé le mot wrap en clip, j'ai pu le redimensionner dans une étiquette avec zéro ligne. Ce serait bien si cela était documenté.
DesignatedNerd
12

Dans Swift 3 (par programmation), je devais faire ceci:

let lbl = UILabel()
lbl.numberOfLines = 0
lbl.lineBreakMode = .byClipping
lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
lbl.font = UIFont.systemFont(ofSize: 15)
Naloiko Eugène
la source
5

Vous pouvez écrire comme

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

Vous pouvez calculer le nombre de lignes comme ça

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

J'espère que cela vous aidera :-) en attendant votre réponse

Birju
la source
donc si j'ai défini le nombre de lignes sur mon étiquette, le texte serait alors automatiquement rétréci?
Lukas
si votre contenu est hors de la largeur, il prendra la ligne suivante
Birju
hey j'ai fait comme vous l'avez suggéré, mais ça ne marche pas, pourquoi le nombre de lignes m'aiderait?
Lukas
vous avez raison j'ai essayé ce n'est pas utile mais j'ai trouvé une solution pour vous faites comme ça ma prochaine réponse
Birju
lbl.adjustsFontSizeToFitWidth = OUI; A travaillé pour moi!
Développeur
4

Enfin, je n'ai pas trouvé ma réponse. Et je pense que la réduction automatique ne fonctionne pas pour plusieurs lignes. J'ai fini par utiliser la suggestion dans ce lien: autoshrink sur un UILabel avec plusieurs lignes

Les solutions sont de calculer la hauteur du texte à une largeur donnée et si le texte est plus grand, de réduire la taille de la police, puis de recommencer jusqu'à ce que la hauteur soit égale ou inférieure à la taille requise.

Je ne comprends pas pourquoi cela devrait être si difficile à mettre en œuvre. Si quelque chose me manque, tout le monde est invité à me corriger :)

Lukas
la source
Comme pour les autres réponses ici, la principale chose qui manquait était que vous deviez définir Word Wrapping sur "Clip". C'est contre-intuitif, mais cela est nécessaire pour qu'un UILabel se rétrécisse automatiquement comme vous le souhaitez. Cela fonctionne avec un UILabel multiligne.
Duncan Babbage
4

Ceci est pour Swift 3 exécutant Xcode 8.2.1 (8C1002)

La meilleure solution que j'ai trouvée est de définir une largeur fixe dans votre Storyboard ou IB sur l'étiquette. Définissez vos contraintes avec une contrainte aux marges. Dans votre viewDidLoad, ajoutez les lignes de code suivantes:

override func viewDidLoad() {
            super.viewDidLoad()

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

étiqueter les contraintes à la marge

contraintes d'étiquette de largeur fixe à la marge

inspecteur d'attributs

Cela a fonctionné comme un charme et il ne déborde pas sur une nouvelle ligne et réduit le texte pour l'adapter à la largeur de l'étiquette sans aucun problème étrange et fonctionne dans Swift 3.

Rob Mcelvenny
la source
4

C'est une excellente question, car il semble que cela fasse désormais partie de la UIKitfonctionnalité intégrée ou d'un cadre connexe. Voici un bon exemple visuel de la question:

Animation de redimensionnement de la police

Il n'y a pas de solution facile, mais c'est certainement possible. Une façon de procéder consiste à essayer par programme différentes tailles de police jusqu'à ce que vous en trouviez une qui se rapproche raisonnablement des limites de la vue. Vous pouvez accomplir cela avec la boundingRect()fonction de NSStringou NSAttributedString. Par exemple:

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

Vous pouvez faire une recherche binaire pour être plus efficace qu'une approche de force brute complète. Il existe également des considérations un peu plus complexes, notamment un habillage de mots correct et des performances de mise en cache des polices iOS, si vous recherchez quelque chose de vraiment robuste.

Si vous vous souciez uniquement d'afficher le texte à l'écran de manière simple, j'ai développé une implémentation robuste dans Swift, que j'utilise également dans une application de production. C'est une UIViewsous - classe avec une mise à l'échelle automatique et efficace des polices pour tout texte d'entrée, y compris plusieurs lignes. Pour l'utiliser, vous feriez simplement quelque chose comme:

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

C'est tout! Vous pouvez trouver la source complète ici: https://github.com/FlickType/AccessibilityKit

J'espère que cela t'aides!

Kosta Eleftheriou
la source
1
Nov 2018: Apparaît le FlickType et AccessibilityKit est devenu privé ou est supprimé.
Chris Paveglio
3

Dans iOS 9, je devais simplement:

  1. Ajoutez des contraintes à gauche et à droite de l'étiquette à la vue de supervision.
  2. Réglez le mode de saut de ligne sur écrêtage dans IB.
  3. Définissez le nombre de lignes sur 1 dans IB.

Quelqu'un a recommandé de définir le nombre de lignes sur 0, mais pour moi, cela a simplement fait passer l'étiquette sur plusieurs lignes ...

Nick Yap
la source
Cela a fait l'affaire pour moi. Je venais de sélectionner un UILabelet un UITextFielddans une cellule statique et j'ai cliqué sur "Résoudre les problèmes de mise en page automatique" et "Ajouter les contraintes manquantes". Tout était aligné, mais Autoshrink avait besoin de connaître la distance par rapport à l'étiquette, pour laquelle "Ajouter des contraintes manquantes" n'ajoutait pas de contrainte.
Adrian
2

Je pense que vous pouvez écrire le code ci-dessous après 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];

Cela fonctionne bien avec moi, utilisez-le

iDhaval
la source
1
merci, mais cela ne calculera pas ou ne réduira pas la police au minimum nécessaire si je comprends bien, et pourquoi votre police minimale est-elle plus grande que la normale?
Lukas
2

Deux ans plus tard, et ce problème est toujours d'actualité ...

Dans iOS 8 / XCode 6.1, je trouvais parfois que mon UILabel(créé dans un UITableViewCell, avec AutoLayout activé et des contraintes flexibles pour qu'il y ait beaucoup d'espace) ne se redimensionnait pas pour s'adapter à la chaîne de texte.

La solution, comme les années précédentes, était de définir le texte, puis d' appeler sizeToFit.

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

(Soupir.)

Mike Gledhill
la source
1

Voici comment faire: Supposons que le message suivant est l'étiquette que vous souhaitez obtenir l'effet désiré.Maintenant, essayez ces simples lignes de codes:

    //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
la source
hé merci pour votre réponse, mais je n'ai pas besoin de calculer la hauteur de l'étiquette, j'ai une taille fixe, et en fonction de cela, ma police doit devenir plus petite si nécessaire.
Lukas
1

ne fonctionne pas si numberOfLines > 1 ce que j'ai fait a créé une condition comme celle-ci-

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

Arriver en retard à la fête, mais comme j'avais l'exigence supplémentaire d'avoir un mot par ligne, cet ajout a fait l'affaire pour moi:

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

Apple Docs dit:

Normalement, le texte de l'étiquette est dessiné avec la police que vous spécifiez dans la propriété font. Cependant, si cette propriété est définie sur OUI et que le texte de la propriété text dépasse le rectangle de délimitation de l'étiquette, le récepteur commence à réduire la taille de la police jusqu'à ce que la chaîne corresponde ou que la taille de police minimale soit atteinte. Dans iOS 6 et versions antérieures, cette propriété est effective uniquement lorsque la propriété numberOfLines est définie sur 1.

Mais c'est un mensonge. Un mensonge je vous dis! C'est vrai pour toutes les versions iOS. Plus précisément, cela est vrai lorsque vous utilisez un UILabeldans un UICollectionViewCellpour lequel la taille est déterminée par des contraintes ajustées dynamiquement à l'exécution via une mise en page personnalisée (ex.self.menuCollectionViewLayout.itemSize = size ).

Ainsi, lorsqu'il est utilisé en conjonction avec adjustsFontSizeToFitWidthet minimumScaleFactor, comme mentionné dans les réponses précédentes, le réglage par programme numberOfLinesbasé sur le nombre de mots a résolu le problème de la réduction automatique. Faire quelque chose de similaire basé sur le nombre de mots ou même le nombre de caractères peut produire une solution «assez proche».

Justin Whitney
la source
0

Dans Swift 4 (par programmation):

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ć
la source
0

Swift 4, Xcode 9.4.1

La solution qui a fonctionné pour moi: j'avais une étiquette dans une cellule de vue de collection et le texte de l'étiquette était coupé. Définissez les attributs comme ci-dessous sur Storyboard

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