8
votes

Redimensionner Uilabel pour s'adapter à Word Wrap

Cela fait partie d'une application iPhone mais devrait s'appliquer au cacao écrit à l'OBJC en général.

J'ai un Uilabel tenant diverses quantités de texte (de caractères simples à plusieurs phrases). Le texte doit toujours être affiché dans la police la plus importante possible qui correspond à tout le texte de l'Uilabel. Le nombre maximum de lignes est défini sur 4 et le mode de rupture de ligne est défini sur Word Wrap. P>

Étant donné que plusieurs lignes sont utilisées, RéglagesFontSizetofitWidth ne fonctionnera pas pour redimensionner le texte. P>

Ainsi, j'utilise une boucle pour déterminer la plus grande taille de police possible pour chaque chaîne en tant que telle: p>

The
Experience
foo


0 commentaires

5 Réponses :


13
votes

Voici la voie la plus élégante (encore un peu pirate) que j'ai trouvé pour faire ce travail:

  1. diviser la chaîne en mots
  2. Calculez la largeur de chaque mot en utilisant la taille de police actuelle
  3. Réduisez la taille de la chaîne jusqu'à ce que chaque mot s'adapte à une ligne

    La consommation de ressources est suffisamment basse pour que cela fonctionne même dans UitailViews plein de chaînes édité de cette manière.

    Voici le nouveau code: xxx


1 commentaires

Parce que tailleWithfont: est devenu obsolète avec iOS 7, vous devez le remplacer par LimiteDecwithSize: .



3
votes

Vous pouvez utiliser le code ci-dessus dans une catégorie pour Uilabel

Uilabel + RightFontSize.h P>

@implementation UILabel (UILabel_AdjustFontSize)

- (void) adjustsFontSizeToFitWidthWithMultipleLinesFromFontWithName:(NSString*)fontName size:(NSInteger)fsize andDescreasingFontBy:(NSInteger)dSize{

    //Largest size used  
    self.font = [UIFont fontWithName:fontName size:fsize];

    //Calculate size of the rendered string with the current parameters
    float height = [self.text sizeWithFont:self.font
                    constrainedToSize:CGSizeMake(self.bounds.size.width,99999) 
                        lineBreakMode:UILineBreakModeWordWrap].height;

    //Reduce font size by dSize while too large, break if no height (empty string)
    while (height > self.bounds.size.height && height != 0) {   
        fsize -= dSize;
        self.font = [UIFont fontWithName:fontName size:fsize];   
        height = [self.text sizeWithFont:self.font 
                  constrainedToSize:CGSizeMake(self.bounds.size.width,99999) 
                      lineBreakMode:UILineBreakModeWordWrap].height;
    };

    // Loop through words in string and resize to fit
    for (NSString *word in [self.text componentsSeparatedByString:@" "]) {
        float width = [word sizeWithFont:self.font].width;
        while (width > self.bounds.size.width && width != 0) {
            fsize -= dSize;
            self.font = [UIFont fontWithName:fontName size:fsize];
            width = [word sizeWithFont:self.font].width;            
        }
    }
}

@end


1 commentaires

J'ai essayé votre code, va dans une boucle infinie dans la déclaration.



4
votes

Voici ma version de la réponse de 0x90 dans une catégorie: xxx


0 commentaires

1
votes

C'est une excellente question, et vous penseriez qu'utilisant la plus grande taille de police possible sans casser les mots, ferait partie de la fonctionnalité UIKIT intégrée ou un cadre associé. Voici un bon exemple visuel de la question:

Animation de redimensionnement des polices < / p>

Comme décrit par d'autres personnes, l'astuce consiste à effectuer la recherche de la taille des mots individuels, ainsi que le texte entier dans son ensemble. En effet, lorsque vous spécifiez une largeur pour dessiner des mots simples dans, les méthodes de dimensionnement enfreignent les mots jusqu'à ce qu'ils n'ont pas d'autre choix - vous leur demandez de dessiner une chaîne "incassable", avec une taille de police spécifique, dans une région cela ne convient tout simplement pas.

au cœur de ma solution de travail, j'utilise la fonction de recherche binaire suivante: xxx

Ce seul n'est pas assez bien que. Vous devez l'utiliser pour d'abord trouver la taille maximale qui conviendra au mot le plus long à l'intérieur des limites. Une fois que vous avez cela, continuez à chercher une taille plus petite jusqu'à ce que tout le texte s'adapte. De cette façon, aucun mot ne sera jamais rompu. Il existe des considérations supplémentaires qui sont un peu plus impliquées, notamment de trouver ce que le mot le plus long est réellement (il y a des gotchas!) Et des performances de mise en cache de polices IOS.

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

c'est ça! Vous pouvez trouver le code source complet ici: https://github.com/flicktype/accessibilekit

J'espère que cela aide!


0 commentaires

0
votes

Extension Uilabel à Swift 4 Basé sur la réponse de 0x90:

func adjustFontSizeToFit() {
    guard var font = self.font, let text = self.text else { return }
    let size = self.frame.size
    var maxSize = font.pointSize
    while maxSize >= self.minimumScaleFactor * self.font.pointSize {
        font = font.withSize(maxSize)
        let constraintSize = CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude)
        let textRect = (text as NSString).boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : font], context: nil)
        let labelSize = textRect.size
        if labelSize.height <= size.height {
            self.font = font
            self.setNeedsLayout()
            break
        }
        maxSize -= 1
    }
    self.font = font;
    self.setNeedsLayout()
}


0 commentaires