Modification dynamique de la taille de la police de UILabel
J'ai actuellement un UILabel
:
factLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 100)];
factLabel.text = @"some text some text some text some text";
factLabel.backgroundColor = [UIColor clearColor];
factLabel.lineBreakMode = UILineBreakModeWordWrap;
factLabel.numberOfLines = 10;
[self.view addSubview:factLabel];
Tout au long de la vie de mon application iOS, factLabel
obtient un tas de valeurs différentes. Certains avec plusieurs phrases, d'autres avec seulement 5 ou 6 mots.
Comment puis-je configurer le UILabel
de sorte que la taille de la police change pour que le texte corresponde toujours aux limites que j'ai définies?
12 réponses
Ligne unique:
factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;
Le code ci-dessus ajustera la taille de police de votre texte à (par exemple) 8
en essayant d'adapter votre texte dans l'étiquette.
numberOfLines = 1
est obligatoire.
Plusieurs lignes:
Pour numberOfLines > 1
Il existe une méthode pour déterminer la taille du texte final à travers les méthodes UIKit addition de {[23] NSString, par exemple:
CGSize lLabelSize = [yourText sizeWithFont: factLabel.font forWidth:factLabel.frame.size.width lineBreakMode:factLabel.lineBreakMode];
Après, vous pouvez simplement redimensionner votre étiquette en utilisant résultant lLabelSize
, par exemple (en supposant que vous ne changera que la hauteur de l'étiquette):
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, factLabel.frame.size.width, lLabelSize.height);
IOS6
Ligne unique:
Depuis iOS6, minimumFontSize
est obsolète. La ligne
factLabel.minimumFontSize = 8.;
Peut être changé en:
factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;
IOS7
Plusieurs lignes:
À partir d'iOS7, {[11] } devient obsolète. Le cas multiligne est réduit à:
factLabel.numberOfLines = 0;
factLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(factLabel.frame.size.width, CGFLOAT_MAX);
CGSize expectSize = [factLabel sizeThatFits:maximumLabelSize];
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, expectSize.width, expectSize.height);
minimumFontSize
a été obsolète avec iOS 6. Vous pouvez utiliser minimumScaleFactor
.
yourLabel.adjustsFontSizeToFitWidth=YES;
yourLabel.minimumScaleFactor=0.5;
Cela prendra soin de votre taille de police en fonction de la largeur de l'étiquette et du texte.
Basé sur la réponse de @Eyal Ben Dov, vous pouvez créer une catégorie pour la rendre flexible à utiliser dans une autre application de la vôtre.
Obs.: J'ai mis à jour son code pour le rendre compatible avec iOS 7
-fichier d'en-Tête
#import <UIKit/UIKit.h>
@interface UILabel (DynamicFontSize)
-(void) adjustFontSizeToFillItsContents;
@end
-Fichier D'implémentation
#import "UILabel+DynamicFontSize.h"
@implementation UILabel (DynamicFontSize)
#define CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE 35
#define CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE 3
-(void) adjustFontSizeToFillItsContents
{
NSString* text = self.text;
for (int i = CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE; i>CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE; i--) {
UIFont *font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];
CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
if (rectSize.size.height <= self.frame.size.height) {
self.font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
break;
}
}
}
@end
-l'Utilisation de
#import "UILabel+DynamicFontSize.h"
[myUILabel adjustFontSizeToFillItsContents];
Santé
C'est 2015. Je devais aller trouver un article de blog qui expliquerait comment le faire pour la dernière version d'iOS et XCode avec Swift afin que cela fonctionne avec plusieurs lignes.
- définissez " Autoshrink "sur" Taille de police minimale."
- Définir la police à la plus grande taille de police souhaitable (j'ai choisi 20)
- Changer " sauts de ligne "de" Wrap Word "à" tronquer la queue."
Source: http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/
Seule ligne- Il y a deux façons, vous pouvez simplement changer.
1 - De Façon Pragmatique (Swift 3)
Ajoutez simplement le code suivant
yourLabel.numberOfLines = 1;
yourLabel.minimumScaleFactor = 0.7;
yourLabel.adjustsFontSizeToFitWidth = true;
2-Utilisation de l'inspecteur D'attributs UILabel
i- Select your label- Set number of lines 1.
ii- Autoshrink- Select Minimum Font Scale from drop down
iii- Set Minimum Font Scale value as you wish , I have set 0.7 as in below image. (default is 0.5)
Version Swift:
textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5
Voici une extension Swift pour UILabel. Il exécute un algorithme de recherche binaire pour redimensionner la police en fonction de la largeur et de la hauteur des limites de l'étiquette. Testé pour fonctionner avec iOS 9 et autolayout.
Utilisation: où <label>
est votre UILabel prédéfini qui doit être redimensionné
<label>.fitFontForSize()
Par défaut, cette fonction recherche dans la plage de tailles de police 5pt et 300pt et définit la police pour adapter son texte "parfaitement" dans les limites (précis dans 1.0 pt). Vous pouvez définir les paramètres de sorte qu'il, par exemple, Recherche entre 1pt et la taille de police actuelle de l'étiquette avec précision dans 0.1 pts de la manière suivante:
<label>.fitFontForSize(1.0, maxFontSize: <label>.font.pointSize, accuracy:0.1)
Copier/Coller le code suivant dans votre fichier
extension UILabel {
func fitFontForSize(var minFontSize : CGFloat = 5.0, var maxFontSize : CGFloat = 300.0, accuracy : CGFloat = 1.0) {
assert(maxFontSize > minFontSize)
layoutIfNeeded() // Can be removed at your own discretion
let constrainedSize = bounds.size
while maxFontSize - minFontSize > accuracy {
let midFontSize : CGFloat = ((minFontSize + maxFontSize) / 2)
font = font.fontWithSize(midFontSize)
sizeToFit()
let checkSize : CGSize = bounds.size
if checkSize.height < constrainedSize.height && checkSize.width < constrainedSize.width {
minFontSize = midFontSize
} else {
maxFontSize = midFontSize
}
}
font = font.fontWithSize(minFontSize)
sizeToFit()
layoutIfNeeded() // Can be removed at your own discretion
}
}
REMARQUE: chacun des appels layoutIfNeeded()
peut être supprimé à votre propre discrétion
C'est un peu pas sophistiqué mais cela devrait fonctionner, par exemple, disons que vous voulez plafonner votre uilabel à 120x120, avec une taille de police maximale de 28:
magicLabel.numberOfLines = 0;
magicLabel.lineBreakMode = NSLineBreakByWordWrapping;
...
magicLabel.text = text;
for (int i = 28; i>3; i--) {
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:(CGFloat)i] constrainedToSize:CGSizeMake(120.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
if (size.height < 120) {
magicLabel.font = [UIFont systemFontOfSize:(CGFloat)i];
break;
}
}
Envoyez simplement le message sizeToFit à L'UITextView. Il ajustera sa propre hauteur pour s'adapter à son texte. Il ne changera pas sa propre largeur ou origine.
[textViewA1 sizeToFit];
Version Swift 2.0:
private func adapteSizeLabel(label: UILabel, sizeMax: CGFloat) {
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
let maximumLabelSize = CGSizeMake(label.frame.size.width, sizeMax);
let expectSize = label.sizeThatFits(maximumLabelSize)
label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, expectSize.width, expectSize.height)
}
Cette solution fonctionne pour multiligne:
Après avoir suivi plusieurs articles, et nécessitant une fonction qui mettrait automatiquement à l'échelle le texte et ajusterait le nombre de lignes pour mieux s'adapter à la taille de l'étiquette donnée, j'ai écrit une fonction moi-même. (IE. une chaîne courte s'adapterait bien sur une ligne et utiliserait une grande quantité du cadre de l'étiquette, alors qu'une longue forte se diviserait automatiquement sur 2 ou 3 lignes et ajusterait la taille en conséquence)
N'hésitez pas à le réutiliser et à le modifier au besoin. Faire bien sûr, vous l'appelez après viewDidLayoutSubviews
a terminé de sorte que le cadre d'étiquette initial a été défini.
+ (void)setFontForLabel:(UILabel *)label withMaximumFontSize:(float)maxFontSize andMaximumLines:(int)maxLines {
int numLines = 1;
float fontSize = maxFontSize;
CGSize textSize; // The size of the text
CGSize frameSize; // The size of the frame of the label
CGSize unrestrictedFrameSize; // The size the text would be if it were not restricted by the label height
CGRect originalLabelFrame = label.frame;
frameSize = label.frame.size;
textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize: fontSize]}];
// Work out the number of lines that will need to fit the text in snug
while (((textSize.width / numLines) / (textSize.height * numLines) > frameSize.width / frameSize.height) && (numLines < maxLines)) {
numLines++;
}
label.numberOfLines = numLines;
// Get the current text size
label.font = [UIFont systemFontOfSize:fontSize];
textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:@{NSFontAttributeName : label.font}
context:nil].size;
// Adjust the frame size so that it can fit text on more lines
// so that we do not end up with truncated text
label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.width);
// Get the size of the text as it would fit into the extended label size
unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;
// Keep reducing the font size until it fits
while (textSize.width > unrestrictedFrameSize.width || textSize.height > frameSize.height) {
fontSize--;
label.font = [UIFont systemFontOfSize:fontSize];
textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:@{NSFontAttributeName : label.font}
context:nil].size;
unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;
}
// Set the label frame size back to original
label.frame = originalLabelFrame;
}
Voici le code de remplissage d'une sous-classe UILabel qui implémente le changement de taille de police animée:
@interface SNTextLayer : CATextLayer
@end
@implementation SNTextLayer
- (void)drawInContext:(CGContextRef)ctx {
// We override this to make text appear at the same vertical positon as in UILabel
// (otherwise it's shifted tdown)
CGFloat height = self.bounds.size.height;
float fontSize = self.fontSize;
// May need to adjust this somewhat if it's not aligned perfectly in your implementation
float yDiff = (height-fontSize)/2 - fontSize/10;
CGContextSaveGState(ctx);
CGContextTranslateCTM(ctx, 0.0, yDiff);
[super drawInContext:ctx];
CGContextRestoreGState(ctx);
}
@end
@interface SNAnimatableLabel ()
@property CATextLayer* textLayer;
@end
@interface SNAnimatableLabel : UILabel
- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration;
@end
@implementation SNAnimatableLabel
- (void)awakeFromNib {
[super awakeFromNib];
_textLayer = [SNTextLayer new];
_textLayer.backgroundColor = self.backgroundColor.CGColor;
_textLayer.foregroundColor = self.textColor.CGColor;
_textLayer.font = CGFontCreateWithFontName((CFStringRef)self.font.fontName);
_textLayer.frame = self.bounds;
_textLayer.string = self.text;
_textLayer.fontSize = self.font.pointSize;
_textLayer.contentsScale = [UIScreen mainScreen].scale;
[_textLayer setPosition: CGPointMake(CGRectGetMidX(_textLayer.frame), CGRectGetMidY(_textLayer.frame))];
[_textLayer setAnchorPoint: CGPointMake(0.5, 0.5)];
[_textLayer setAlignmentMode: kCAAlignmentCenter];
self.textColor = self.backgroundColor;
// Blend text with background, so that it doens't interfere with textlayer text
[self.layer addSublayer:_textLayer];
self.layer.masksToBounds = NO;
}
- (void)setText:(NSString *)text {
_textLayer.string = text;
super.text = text;
}
- (void)layoutSubviews {
[super layoutSubviews];
// Need to enlarge the frame, otherwise the text may get clipped for bigger font sizes
_textLayer.frame = CGRectInset(self.bounds, -5, -5);
}
- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration {
[CATransaction begin];
[CATransaction setAnimationDuration:duration];
_textLayer.fontSize = fontSize;
[CATransaction commit];
}