65 votes

Comment définir la taille de la police pour remplir la hauteur de UILabel?

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 ?

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.

42voto

Conaaando Points 509

J'ai eu exactement le même problème et, grâce à ce fil et à l'algorithme de Joel, j'ai pu le résoudre. :-)

Voici mon code en Swift. Je suis sur iOS 8 + Autolayout.

Problème:

  1. Les utilisateurs saisissent des dépenses :

application 123

  1. Lorsque les utilisateurs appuient sur le bouton 'vérifier', un menu apparaît en bas, poussant tout vers le haut de l'écran (réduisant la taille des éléments, y compris l'étiquette) :

application 123

Après la correction :

application 123

C'est exactement ce que le designer avait en tête... :)

application xScope :)

J'ai sous-classé UILabel et j'ai remplacé layoutSubviews. Ensuite, à chaque fois que la taille du UILabel est modifiée, la taille de la police est recalculée :

//
//  LabelWithAdaptiveTextHeight.swift
//  123
//
//  Créé par https://github.com/backslash-f le 19/12/14.
//

/*
Conçu en pensant aux UILabels à une seule ligne, cette sous-classe 'redimensionne' le texte de l'étiquette (elle modifie la taille de la police de l'étiquette)
à chaque fois que sa taille (frame) est modifiée. Cela 'ajuste' le texte à la nouvelle hauteur, évitant ainsi le rognage du texte.
Félicitations à ce fil de discussion Stack Overflow : bit.ly/setFontSizeToFillUILabelHeight
*/

import Foundation
import UIKit

class LabelWithAdaptiveTextHeight: UILabel {

    override func layoutSubviews() {
        super.layoutSubviews()
        font = fontToFitHeight()
    }

    // Renvoie une UIFont qui s'adapte à la nouvelle hauteur de l'étiquette.
    private func fontToFitHeight() -> UIFont {

        var minFontSize: CGFloat = DISPLAY_FONT_MINIMUM // CGFloat 18
        var maxFontSize: CGFloat = DISPLAY_FONT_BIG     // CGFloat 67
        var fontSizeAverage: CGFloat = 0
        var textAndLabelHeightDiff: CGFloat = 0

        while (minFontSize <= maxFontSize) {

            fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2

            // Abandonner si le texte s'avère être nil
            guard text?.characters.count > 0 else {
              break
            }

            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)
    }
}

37voto

Kashif Points 802

Il y a une solution plus simple. Il suffit d'ajouter les lignes ci-dessous et comme par magie, l'étiquette ajuste sa taille de police pour s'adapter à la hauteur de l'étiquette également :

SWIFT 3 :

label.minimumScaleFactor = 0.1    //ou tout ce qui convient à vos besoins
label.adjustsFontSizeToFitWidth = true    
label.lineBreakMode = .byClipping
label.numberOfLines = 0

1 votes

La clé ici était "byClipping". J'avais "WordWrap" défini dans l'interface builder, ce qui a empêché tous les paramètres d'avoir un quelconque effet.

36voto

Joel Fischer Points 2476

Voici comment j'ai fait, car la réponse de DGund ne fonctionnait pas pour moi, elle convenait à la largeur, mais je voulais qu'elle s'adapte à la hauteur.

+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(CGSize)labelSize withMinimumSize:(NSInteger)minSize
{
    UIFont *tempFont = nil;
    NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    NSInteger tempMin = minSize;
    NSInteger tempMax = 256;
    NSInteger mid = 0;
    NSInteger difference = 0;

    while (tempMin <= tempMax) {
        mid = tempMin + (tempMax - tempMin) / 2;
        tempFont = [UIFont fontWithName:fontName size:mid];
        difference = labelSize.height - [testString sizeWithFont:tempFont].height;

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

Cela prendra un nom de police, une taille (cela ne doit pas nécessairement être un UILabel, théoriquement, mais je l'ai toujours utilisé avec un UILabel), et une taille minimum (vous pourriez également utiliser une taille maximum, remplacez simplement le 256 par le paramètre de taille maximum). Cela testera essentiellement chaque taille de police entre la taille minimale et maximale de la police et renverra celle qui est à ou juste en dessous de la hauteur cible.

L'utilisation est explicite, mais ressemble à ceci :

self.myLabel.font = [self findAdaptiveFontWithName:@"HelveticaNeue-UltraLight" forUILabelSize:self.myLabel.frame.size withMinimumSize:30];

Vous pouvez également en faire une méthode de classe sur UIFont (c'est ce que j'ai fait).

ÉDITER : Suite à une suggestion, j'ai supprimé la boucle for et ai passé un peu de temps à le rendre plus efficace avec une routine de recherche binaire. J'ai effectué plusieurs vérifications pour m'assurer absolument que la police finira par s'adapter dans le label. Lors de tests initiaux, cela semble fonctionner.

24voto

DGund Points 2458

Éditer: Consultez la superbe réponse de Joel Fischer pour obtenir la taille correcte de manière programmatique!

Vous pouvez définir la police pour remplir automatiquement la taille d'une étiquette, et éventuellement ne pas descendre en dessous d'une taille de police minimale. Il suffit de définir adjustsFontSizeToFitWidth sur OUI. Consultez la Référence de la classe UILabel si vous avez besoin de plus d'informations.

Bien que le booléen s'appelle "adjustsFontSizeToFitWidth," cela signifie vraiment la plus grande taille pour la hauteur de l'étiquette, qui restera sur une seule ligne de l'étiquette (ou sur autant de lignes que vous spécifiez).

14voto

Fjohn Points 1582

Pour adapter le texte en fonction de la hauteur de mon libellé, j'ai adapté la méthode de Joel à Swift

func optimisedfindAdaptiveFontWithName(fontName:String, label:UILabel!, minSize:CGFloat,maxSize:CGFloat) -> UIFont!
{

    var tempFont:UIFont
    var tempHeight:CGFloat
    var tempMax:CGFloat = maxSize
    var tempMin:CGFloat = minSize

    while (ceil(tempMin) != ceil(tempMax)){
        let testedSize = (tempMax + tempMin) / 2

        tempFont = UIFont(name:fontName, size:testedSize)
        let attributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : tempFont])

        let textFrame = attributedString.boundingRectWithSize(CGSize(width: label.bounds.size.width, height: CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin , context: nil)

        let difference = label.frame.height - textFrame.height
        println("\(tempMin)-\(tempMax) - testé : \(testedSize) --> différence : \(difference)")
        if(difference > 0){
            tempMin = testedSize
        }else{
            tempMax = testedSize
        }
    }

    //retourner la taille -1 (pour avoir assez d'espace à droite et à gauche)
    return UIFont(name: fontName, size: tempMin - 1)
}

et je l'utilise de cette manière :

myLabel.font = optimisedfindAdaptiveFontWithName("Helvetica", label: myLabel, minSize: 10, maxSize: 38)
    println("\(myLabel.font)")

0 votes

J'ai réussi à le faire fonctionner de manière impressionnante, sauf lorsque j'utilise des lettres minuscules. Parfois, elles sont juste en dehors du cadre de mon étiquette :<

0 votes

Vraiment fonctionne, mais var tempHeight:CGFloat n'est pas nécessaire.

1 votes

Mais....Je l'ai utilisé comme une extension UIFont, pas changé, des codes comme aLabel.font.optimisedfindAdaptiveFontWithName(".SFUIText-Reg‌​ular", label: fontLabel, minSize: 10, maxSize: 100). Quel est le problème?

Prograide.com

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.

Powered by:

X