J'ai vu plusieurs exemples pour changer la taille d'un UILabel.
Voici ce que j'aimerais faire : Modifier la taille de la police pour que le texte soit aussi grand que possible dans la nouvelle hauteur.
Des indications ?
J'ai vu plusieurs exemples pour changer la taille d'un UILabel.
Voici ce que j'aimerais faire : Modifier la taille de la police pour que le texte soit aussi grand que possible dans la nouvelle hauteur.
Des indications ?
Bonne nouvelle,
Il vous suffit d'itérer (quelques fois) en utilisant une recherche de ratio.
guess = guess * ( desiredHeight / guessHeight )
Voici une solution IBDesignable
complète.
Remarque : lors de la collaboration avec des designers ou des typographes, vous devrez définir le suivi / l'étirement des polices. (Il est absurde qu'Apple ne l'inclut pas.) StyledLabel
inclut également le suivi / l'étirement.
// l'appel fontToFitHeight TROUVE LA TAILLE DE POINT POUR "REMPLIR À LA HAUTEUR".
// Utilisez simplement l'auto-layout pour définir le cadre À LA HAUTEUR EFFECTIVE
// que vous souhaitez pour le type SUR N'IMPORTE QUEL APPAREIL
// DE PLUS, vous pouvez définir:
// le suivi (c'est la quantité globale d'espace entre toutes les lettres)
// et l'étirement (serrer ou étirer les lettres horizontalement)
// Remarque : le suivi et l'étirement SONT AFFICHÉS EN DIRECT DANS LE STORYBOARD
// WTT crazyrems http://stackoverflow.com/a/37300130/294884
import UIKit
@IBDesignable
class StyledLabel: UILabel
{
@IBInspectable var tracking:CGFloat = 0.8
// valeurs entre environ 0,7 à 1,3. un signifie normal.
@IBInspectable var stretching:CGFloat = -0.1
// valeurs entre environ -.5 à .5. zéro signifie normal.
override func awakeFromNib()
{
tweak()
}
override func prepareForInterfaceBuilder()
{
tweak()
}
override func layoutSubviews()
{
super.layoutSubviews()
font = fontToFitHeight()
}
private func fontToFitHeight() -> UIFont
{
/* Apple n'a pas inclus une chose de base nécessaire dans le traitement du texte : adapter le texte à la hauteur. Voici la manière la plus simple et la plus rapide de le faire :
guess = guess * ( desiredHeight / guessHeight )
C'est vraiment tout ce qu'il y a à faire. Le reste du code dans cette routine est des sauvegardes. De plus, la routine itère quelques fois, ce qui est inoffensif, pour prendre en charge d'éventuels problèmes de dimensionnement non linéaire bizarres avec des polices étranges. */
guard text?.characters.count > 0 else { return font }
let desiredHeight:CGFloat = frame.size.height
guard desiredHeight>1 else { return font }
var guess:CGFloat
var guessHeight:CGFloat
print("recherche de... ", desiredHeight)
guess = font.pointSize
if (guess>1&&guess<1000) { guess = 50 }
guessHeight = sizeIf(guess)
if (guessHeight==desiredHeight)
{
print("fluke, correspondance exacte au sein des limites de calcul en virgule flottante, en avance")
return font.fontWithSize(guess)
}
var iterations:Int = 4
/* Il est incroyablement improbable que vous ayez besoin de plus de quatre itérations, "deux" seraient rarement nécessaires. Vous pourriez imaginer une manipulation de glyphe très étrange où la relation est non linéaire (ou quelque chose de bizarre) : c'est la seule raison théorique pour laquelle vous auriez jamais besoin de plus d'une ou deux itérations. Notez que lorsque vous regardez la sortie des itérations, vous verrez parfois/souvent les mêmes valeurs pour le résultat : c'est correct et attendu dans une itération en virgule flottante. */
while(iterations>0)
{
guess = guess * ( desiredHeight / guessHeight )
guessHeight = sizeIf(guess)
if (guessHeight==desiredHeight)
{
print("fluke incroyable, correspondance exacte dans les limites de calcul en virgule flottante en itérant")
return font.fontWithSize(guess)
}
iterations -= 1
}
print("terminé. Dommage qu'Apple ne le fasse pas pour nous!")
return font.fontWithSize(guess)
}
private func sizeIf(pointSizeToTry:CGFloat)->(CGFloat)
{
let s:CGFloat = text!.sizeWithAttributes(
[NSFontAttributeName: font.fontWithSize(pointSizeToTry)] )
.height
print("deviner .. ", pointSizeToTry, " .. " , s)
return s
}
private func tweak()
{
let ats = NSMutableAttributedString(string: self.text!)
let rg = NSRange(location: 0, length: self.text!.characters.count)
ats.addAttribute(
NSKernAttributeName, value:CGFloat(tracking), range:rg )
ats.addAttribute(
NSExpansionAttributeName, value:CGFloat(stretching), range:rg )
self.attributedText = ats
}
}
Une seule ligne appelée dans viewWillAppear fait l'affaire:
testLabel.font = testLabel.font.fontWithSize(testLabel.frame.height * 2/3)
Dans le storyboard, j'ai défini toutes les hauteurs de mes étiquettes par rapport à la hauteur globale de la vue, ce qui permet à la taille de la police de s'adapter dynamiquement à celles-ci.
Remarquez que la taille de la police est en fait égale aux 2/3 de la hauteur de l'étiquette. Si la police que vous utilisez a des queues qui descendent en dessous de la ligne (comme dans y, g, q, p ou j), vous voudrez adapter la taille de la police à un ratio de la hauteur de l'étiquette afin que ces queues ne soient pas coupées. Un ratio de 2/3 fonctionne bien pour Helvetica Neue, mais essayez d'autres ratios en fonction de la police que vous utilisez. Pour les polices sans queues, les chiffres, ou le texte en majuscules, un ratio de 1:1 peut suffire.
Sur la base de la grande réponse de @Conaaando, je l'ai mise à jour pour inclure des paramètres IBDesignable, ce qui permet de la modifier tout au long de l'Interface builder:
Et le code :
//
// TIFFitToHeightLabel.swift
//
import Fondation
import UIKit
@IBDesignable class TIFFitToHeightLabel: UILabel {
@IBInspectable var minFontSize:CGFloat = 12 {
didSet {
font = fontToFitHeight()
}
}
@IBInspectable var maxFontSize:CGFloat = 30 {
didSet {
font = fontToFitHeight()
}
}
override func layoutSubviews() {
super.layoutSubviews()
font = fontToFitHeight()
}
// Retourne une police UIFont qui s'adapte à la hauteur du nouveau label.
private func fontToFitHeight() -> UIFont {
var minFontSize: CGFloat = self.minFontSize
var maxFontSize: CGFloat = self.maxFontSize
var fontSizeAverage: CGFloat = 0
var textAndLabelHeightDiff: CGFloat = 0
while (minFontSize <= maxFontSize) {
fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2
if let labelText: NSString = text {
let labelHeight = frame.size.height
let testStringHeight = labelText.sizeWithAttributes(
[NSFontAttributeName: font.fontWithSize(fontSizeAverage)]
).height
textAndLabelHeightDiff = labelHeight - testStringHeight
if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
if (textAndLabelHeightDiff < 0) {
return font.fontWithSize(fontSizeAverage - 1)
}
return font.fontWithSize(fontSizeAverage)
}
if (textAndLabelHeightDiff < 0) {
maxFontSize = fontSizeAverage - 1
} else if (textAndLabelHeightDiff > 0) {
minFontSize = fontSizeAverage + 1
} else {
return font.fontWithSize(fontSizeAverage)
}
}
}
return font.fontWithSize(fontSizeAverage)
}
}
Cela s'inspire largement de la réponse de Joel Fischer. Sa réponse prend en compte uniquement la hauteur de l'étiquette - j'ai apporté quelques modifications pour prendre également en compte la largeur de l'étiquette (étant donné une chaîne d'entrée), ce que je voulais :
typedef enum
{
kDimensionHeight,
kDimensionWidth,
} DimensionType;
@implementation UIFont (AdaptiveFont)
+ (UIFont *)_adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelDimension:(CGFloat)labelDimension testString:(NSString *)testString dimension:(DimensionType)dimension
{
UIFont *tempFont = nil;
NSInteger tempMin = minSize;
NSInteger tempMax = 256;
NSInteger mid = 0;
NSInteger difference = 0;
CGFloat testStringDimension = 0.0;
while (tempMin <= tempMax) {
@autoreleasepool {
mid = tempMin + (tempMax - tempMin) / 2;
tempFont = [UIFont fontWithName:fontName size:mid];
// déterminer la dimension à tester
if (dimension == kDimensionHeight) {
testStringDimension = [testString sizeWithFont:tempFont].height;
} else {
testStringDimension = [testString sizeWithFont:tempFont].width;
}
difference = labelDimension - testStringDimension;
if (mid == tempMin || mid == tempMax) {
if (difference < 0) {
return [UIFont fontWithName:fontName size:(mid - 1)];
}
return [UIFont fontWithName:fontName size:mid];
}
if (difference < 0) {
tempMax = mid - 1;
} else if (difference > 0) {
tempMin = mid + 1;
} else {
return [UIFont fontWithName:fontName size:mid];
}
}
}
return [UIFont fontWithName:fontName size:mid];
}
+ (UIFont *)adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelSize:(CGSize)labelSize string:(NSString *)string
{
UIFont *adaptiveFont = nil;
NSString *testString = nil;
// obtenir la police, étant donné une hauteur maximale
testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
UIFont *fontConstrainingHeight = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.height testString:testString dimension:kDimensionHeight];
CGSize boundsConstrainingHeight = [string sizeWithFont:fontConstrainingHeight];
CGSize boundsConstrainingWidth = CGSizeZero;
// si la LARGEUR est correcte (tout en contraignant la HAUTEUR), retourner cette police
if (boundsConstrainingHeight.width <= labelSize.width) {
adaptiveFont = fontConstrainingHeight;
} else {
// obtenir la police, étant donné une largeur maximale
// c'est-à-dire fontConstrainingWidth
testString = string;
adaptiveFont = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.width testString:testString dimension:kDimensionWidth];
// Comparaison TEST
boundsConstrainingWidth = [string sizeWithFont:adaptiveFont];
}
return adaptiveFont;
}
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
1 votes
Je viens de réaliser que réaliser une recherche binaire ou autre est totalement inutile. Vous n'avez qu'à itérer (quelques fois) en utilisant une recherche de ratio. C'est tout simple. Je vais coller le code complet dans ma réponse.
1 votes
.. solution complète pour 2016 stackoverflow.com/a/37277874/294884 Code très simple.