38 votes

Comment laisser NSTextField grandir avec le texte en mise en page automatique ?

Avec la mise en page automatique de Lion, il devrait être assez simple de laisser un champ de texte (et donc une étiquette) s'agrandir avec le texte qu'il contient.

Le champ de texte est configuré pour être enveloppé dans Interface Builder.

Quel est le moyen le plus simple et le plus fiable de le faire ?

51voto

Monolo Points 11263

La méthode intrinsicContentSize en NSView renvoie ce que la vue elle-même considère comme sa taille de contenu intrinsèque.

NSTextField calcule cela sans tenir compte de la wraps de sa cellule, de sorte qu'il indique les dimensions du texte s'il est disposé sur une seule ligne.

Par conséquent, une sous-classe personnalisée de NSTextField peut remplacer cette méthode pour renvoyer une meilleure valeur, telle que celle fournie par l'attribut de cellule cellSizeForBounds: méthode :

-(NSSize)intrinsicContentSize
{
    if ( ![self.cell wraps] ) {
        return [super intrinsicContentSize];
    }

    NSRect frame = [self frame];

    CGFloat width = frame.size.width;

    // Make the frame very high, while keeping the width
    frame.size.height = CGFLOAT_MAX;

    // Calculate new height within the frame
    // with practically infinite height.
    CGFloat height = [self.cell cellSizeForBounds: frame].height;

    return NSMakeSize(width, height);
}

// you need to invalidate the layout on text change, else it wouldn't grow by changing the text
- (void)textDidChange:(NSNotification *)notification
{
    [super textDidChange:notification];
    [self invalidateIntrinsicContentSize];
}

2 votes

Cela correspond exactement à ce que je vois. Pour clarifier, le fait d'ignorer la propriété "wraps" de la cellule semble être un bogue dans Lion qui a été corrigé dans Mountain Lion. Donc, si vous visez Lion et les versions supérieures, vous obtiendrez des résultats différents dans les deux systèmes d'exploitation jusqu'à ce que vous appliquiez le correctif pour mettre Lion à niveau.

0 votes

Oui, il s'agit d'un bogue dans Lion. J'aimerais vraiment qu'Apple corrige ces problèmes dans OS X 10.7 && 10.8. Dans mon implémentation, je fais quelques vérifications supplémentaires pour les cas spéciaux (par exemple, si c'est Lion || Si la langue n'est pas l'anglais) et je règle ma hauteur un peu différemment. Néanmoins, ce que Monolo a posté est un bon début.

2 votes

La méthode intrinsicContentSize : n'est pas appelée lorsque vous modifiez le texte qu'elle contient par setStringValue :.

9voto

Lore Points 360

Swift 4

Champ NSTextField éditable et à dimensionnement automatique

Basé sur le post Objective-C de Peter Lapisu

Sous-classe NSTextField ajoutez le code ci-dessous.

override var intrinsicContentSize: NSSize {
    // Guard the cell exists and wraps
    guard let cell = self.cell, cell.wraps else {return super.intrinsicContentSize}

    // Use intrinsic width to jive with autolayout
    let width = super.intrinsicContentSize.width

    // Set the frame height to a reasonable number
    self.frame.size.height = 750.0

    // Calcuate height
    let height = cell.cellSize(forBounds: self.frame).height

    return NSMakeSize(width, height);
}

override func textDidChange(_ notification: Notification) {
    super.textDidChange(notification)
    super.invalidateIntrinsicContentSize()
}

Réglage de self.frame.size.height à "un nombre raisonnable". évite quelques bogues lors de l'utilisation de FLT_MAX , CGFloat.greatestFiniteMagnitude ou de grands nombres. Les bogues se produisent pendant le fonctionnement lorsque l'utilisateur sélectionne le texte dans le champ, il peut faire défiler le texte vers le haut et vers le bas à l'infini. De plus, lorsque l'utilisateur saisit du texte, le NSTextField est masqué jusqu'à ce que l'utilisateur termine l'édition. Enfin, si l'utilisateur a sélectionné l'option NSTextField et tente ensuite de redimensionner la fenêtre, si la valeur du paramètre self.frame.size.height est trop grande, la fenêtre sera suspendue.

4voto

spinacher Points 31

La réponse acceptée est basée sur la manipulation intrinsicContentSize mais cela peut ne pas être nécessaire dans tous les cas. Autolayout augmentera et réduira la hauteur du champ de texte si (a) vous donnez au champ de texte une valeur de preferredMaxLayoutWidth et (b) faire en sorte que le champ ne editable . Ces étapes permettent au champ de texte de déterminer sa largeur intrinsèque et de calculer la hauteur nécessaire à la mise en page automatique. Voir cette réponse y cette réponse pour plus de détails.

De manière encore plus obscure, il découle de la dépendance à l'égard du champ de texte editable qu'autolayout rompra si vous utilisez des liens sur le champ et que vous n'effacez pas l'attribut Conditionally Sets Editable option.

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