J'ai actuellement une 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 la UILabel
de sorte que la taille de la police change de sorte que le texte tienne toujours dans les limites que j'ai définies?
Une seule ligne:
factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;
Le code ci-dessus ajustera la taille de la police de votre texte à (par exemple) 8
en essayant de l'ajuster à l'intérieur de l'étiquette. numberOfLines = 1
est obligatoire.
Plusieurs lignes:
Pour numberOfLines > 1
, il existe une méthode permettant de déterminer la taille du texte final par le biais de méthodes sizeWithFont: ... UIKit de NSString , par exemple:
CGSize lLabelSize = [yourText sizeWithFont:factLabel.font
forWidth:factLabel.frame.size.width
lineBreakMode:factLabel.lineBreakMode];
Après cela, vous pouvez simplement redimensionner votre étiquette en utilisant lLabelSize
résultant, par exemple (en supposant que vous ne changiez que la hauteur de l'étiquette):
factLabel.frame = CGRectMake(factLabel.frame.Origin.x, factLabel.frame.Origin.y, factLabel.frame.size.width, lLabelSize.height);
iOS6
Une seule ligne:
À partir de iOS6, minimumFontSize
est obsolète. La ligne
factLabel.minimumFontSize = 8.;
peut être changé en:
factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;
iOS7
Plusieurs lignes:
À partir de iOS7, sizeWithFont
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
est 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.
Selon la réponse de @Eyal Ben Dov, vous souhaiterez peut-être 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
- Usage
#import "UILabel+DynamicFontSize.h"
[myUILabel adjustFontSizeToFillItsContents];
À votre santé
Une seule ligne - Il y a deux façons de changer.
1- Pragmatiquement (Swift 3)
Ajoutez simplement le code suivant
yourLabel.numberOfLines = 1;
yourLabel.minimumScaleFactor = 0.7;
yourLabel.adjustsFontSizeToFitWidth = true;
2 - Utiliser 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)
Nous sommes en 2015. Je devais trouver un article de blog qui expliquerait comment utiliser la dernière version d'iOS et de XCode avec Swift pour qu'il fonctionne avec plusieurs lignes.
Source: http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/
Version rapide:
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.
SAGE: Où <label>
est votre UILabel prédéfini qui nécessite un redimensionnement de la police.
<label>.fitFontForSize()
Par défaut, cette fonction effectue une recherche dans les tailles de police comprises entre 5 et 300 points et définit la police pour adapter son texte "parfaitement" à l'intérieur des limites (avec une précision de moins de 1,0 point). Vous pouvez définir les paramètres pour que, par exemple, il recherche entre 1pt et la taille de police actuelle du libellé avec précision à l'intérieur de .1pts de la manière suivante :
<label>.fitFontForSize(1.0, maxFontSize: <label>.font.pointSize, accuracy:0.1)
Copiez/Collez 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
}
}
NOTE: Chacun des appels layoutIfNeeded()
peut être supprimé à votre propre discrétion.
Son un peu peu 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 à UITextView. Il ajustera sa propre hauteur pour s'adapter à son texte. Il ne changera pas sa propre largeur ou origine.
[textViewA1 sizeToFit];
Voici le code de remplissage d'une sous-classe UILabel qui implémente un changement de taille de police animé:
@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];
}
Cette solution fonctionne pour multiligne:
Après avoir suivi plusieurs articles et exigé une fonction qui redimensionnerait automatiquement le texte et ajusterait le nombre de lignes pour correspondre au mieux à la taille de l'étiquette donnée, j'ai écrit une fonction moi-même. (c.-à-d. une ficelle courte irait bien sur une ligne et utiliserait une grande partie du cadre de l'étiquette, alors qu'une chaîne forte et longue se scinderait automatiquement en 2 ou 3 lignes et ajusterait la taille en conséquence)
N'hésitez pas à le réutiliser et à modifier au besoin. Assurez-vous de l'appeler une fois que viewDidLayoutSubviews
est terminé afin que le cadre d'étiquette initial ait é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;
}
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)
}