web-dev-qa-db-fra.com

Comment dimensionner un ajustement UILabel en modifiant uniquement la hauteur et non la largeur?

[self.Review sizeToFit];

Résultat avant sizeToFit:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {198, 63}}

Résultat après sizeToFit:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {181, 45}}

Je veux que la largeur reste la même. Je veux juste changer la hauteur. Le masque automatique est

(lldb) po self.Review
(UILabel *) $1 = 0x08bb0fe0 <UILabel: 0x8bb0fe0; frame = (90 20; 181 45); text = 'I'm at Mal Taman Anggrek ...'; clipsToBounds = YES; opaque = NO; autoresize = LM+RM+H; userInteractionEnabled = NO; layer = <CALayer: 0x8bb68b0>>

Je sais qu'il existe un moyen de le faire avec: Comment ajuster et faire la largeur d'un UILabel pour s'adapter à la taille du texte?

Les réponses sont soit étranges (nous devons réapprovisionner les informations de police). Ou pas clair.

Vous devrez également définir une largeur maximale et indiquer à votre programme quoi faire si sizeToFit vous donne une largeur supérieure à ce maximum.

J'utiliserai l'étrange solution d'utiliser sizeWithFont. C'est étrange car UILabel connaît déjà la police de l'étiquette.

En fait, comment se comporte sizeToFit de toute façon? Comment décide-t-on si nous avons besoin d'un UILabel plus fin ou plus grand?

34
Anonymous White

Voilà comment cela se fait. Étant donné que l'étiquette contient déjà les informations sur la police, leur inclusion dans cet appel de méthode est triviale.

CGSize size = [label.text sizeWithFont:label.font
                     constrainedToSize:CGSizeMake(maxWidth, MAXFLOAT)
                         lineBreakMode:UILineBreakModeWordWrap]; 
CGRect labelFrame = label.frame;
labelFrame.size.height = size.height;
label.frame = labelFrame;

Version Swift utilisant le boundingRectWithSize le plus à jour:

let maxHeight = CGFloat.infinity
let rect = label.attributedText?.boundingRectWithSize(CGSizeMake(maxWidth, maxHeight), 
       options: .UsesLineFragmentOrigin, context: nil)
var frame = label.frame
frame.size.height = rect.size.height
label.frame = frame
41
Mundi

Vous pouvez obtenir le même résultat avec sizeThatFits.

CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
CGRect frame = label.frame;
frame.size.height = size.height;
label.frame = frame;

Ou alternativement, avec sizeToFit.

CGRect frame = label.frame;
[label sizeToFit];
frame.size.height = label.frame.size.height;
label.frame = frame;
40
vadimtrifonov

sizeToFit fonctionne très bien. Le seul problème est qu'il est basé sur la taille actuelle du contrôle.

Par exemple, si vous recyclez des cellules de vue tabulaire avec une étiquette, l'étiquette peut avoir été réduite en largeur dans une cellule précédente et donc, l'appel à sizeToFit peut sembler peu fiable.

Réinitialisez simplement la largeur d'origine de votre contrôle avant d'envoyer le message sizeToFit.

17
chrilith

Réponse pour 2017 ...

c = CGSize (largeur: votreLargeur, hauteur: CGFloat.greatestFiniteMagnitude)
result = sizeThatFits (c) .height

Donc...

let t = .... your UITextView
let w = .... your known width of the item

let trueHeight = t.sizeThatFits(
                   CGSize(width: t, height: CGFloat.greatestFiniteMagnitude)).height

C'est ça.


Très souvent, vous voulez connaître la différence en hauteur par rapport à une entrée "normale" sur une ligne .

Cela se produit en particulier si vous créez une sorte de cellules qui n'ont rien à voir avec UTableView (par exemple, une sorte de vue de pile personnalisée). Vous devez définir la hauteur manuellement à un moment donné. Sur votre storyboard, construisez-le comme vous le souhaitez, en utilisant un exemple de texte de n'importe quelle chaîne courte (par exemple, "A") qui bien sûr n'aura qu'une seule ligne dans une situation normale. Ensuite, vous faites quelque chose comme ça ...

func setTextWithSizeCorrection() { // an affaire iOS

    let t = .... your UITextView
    let w = .... your known width of the item

    let oneLineExample = "A"
    let actualText = yourDataSource[row].description.whatever

    // get the height as if with only one line...

    experimental.text = oneLineExample
    let oneLineHeight = t.sizeThatFits(
               CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height

    // get the height with the actual long text...
    // (note that usually, you do not want a one-line minimum)

    experimental.text = (actualText == "") ? oneLineExample : actualText
    let neededHeight = t.sizeThatFits(
              CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height

    experimental.text = actualText

    let delta = neededHeight - oneLineHeight

    set the height of your cell, or whatever it is(standardHeight + delta)
}

Dernier point: l'une des choses vraiment stupides dans iOS est que UITextView a une sorte de marge bizarre à l'intérieur. Cela signifie que vous ne pouvez pas simplement basculer entre UITextViews et les étiquettes; et cela cause de nombreux autres problèmes. Apple n'a pas résolu ce problème au moment de l'écriture. Pour résoudre le problème est difficile: l'approche suivante est généralement OK:

@IBDesignable class UITextViewFixed: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    func setup() {
        textContainerInset = UIEdgeInsets.zero;
        textContainer.lineFragmentPadding = 0;
    }
}

UITextView cassé et inutilisable d'Apple ...

enter image description here

UITextViewFixed qui est, dans la plupart des cas, un correctif acceptable:

enter image description here

(Jaune ajouté pour plus de clarté.)

2
Fattie

Je pense que vous ne devriez pas utiliser le NSStringsize... méthodes, UILabel possède déjà une API pour cela, comme le souligne @vatrif (qui utilise probablement en interne uniquement les méthodes de NSString).

Néanmoins, je pense que l'API de UILabel pourrait être améliorée. C'est pourquoi je pense qu'une catégorie serait la solution la plus élégante:

//  UILabel+Resize.h
@interface UILabel (Resize)
- (void)sizeToFitHeight;
@end

//  UILabel+Resize.m
@implementation UILabel (Resize)
- (void)sizeToFitHeight {
    CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
    CGRect frame = self.frame;
    frame.size.height = size.height;
    self.frame = frame;
}
@end

Juste une chose: je ne suis pas sûr du nom approprié pour cette méthode:

  • sizeToFitHeight?
  • heightToFit?

Commentaires très appréciés, merci!

2
de.

Une API agréée bénéficierait de cet ajout. Simplifiez-vous la vie et ajoutez une extension à la classe UILabel dans Swift comme suit:

extension UILabel {

    func sizeToFitHeight() {
        let size:CGSize = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}
1
dijipiji

Une extension facile pour ce problème pour Swift 3.

extension UILabel {
    func sizeToFitHeight() {
        let size: CGSize = self.sizeThatFits(CGSize.init(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}
1
ndduong

SOLUTION FIXE POUR Swift

Utilisez CGFloat.greatestFiniteMagnitude Pour maxHeight.

let size = CGSize.init(width: yourLabel.frame.size.width,
                       height: CGFloat.greatestFiniteMagnitude)
let rect = errorLabel.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
var frame = errorLabel.frame
frame.size.height = (rect?.size.height)!
errorLabel.frame = frame


OU Créez l'extension UIlabel et appelez la méthode yourLabel. sizeToFitHeight()

extension UILabel {

    func sizeToFitHeight() {
        let maxHeight : CGFloat = CGFloat.greatestFiniteMagnitude
        let size = CGSize.init(width: self.frame.size.width, height: maxHeight)
        let rect = self.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
        var frame = self.frame
        frame.size.height = (rect?.size.height)!
        self.frame = frame
    }

} 
1
MANISH PATHAK

Version Swift 3 de Mundi réponse:

let maxHeight: CGFloat = 10000
let rect = label.attributedText!.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
                                                           options: .usesLineFragmentOrigin,
                                                           context: nil)
var frame = labe.frame
frame.size.height = rect.size.height
label.frame = frame
0
Artem Novichkov