web-dev-qa-db-fra.com

iOS: UIButton redimensionner en fonction de la longueur du texte

Dans le constructeur d'interface, maintenant Command + = redimensionnera un bouton pour adapter son texte. Je me demandais si cela était possible par programmation avant que le bouton ne soit ajouté à la vue.

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12]];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
// I need to know the width needed to accomodate NSStringVariable
[button setTitle:NSStringVariable forState:UIControlStateNormal]; 
// So that I can set the width property of the button before addSubview
[button setFrame:CGRectMake(10, 0, width, fixedHeight)];
[subNavigation addSubview:button];
121
Oh Danny Boy

Dans Xcode 4.5 et supérieur, cela peut maintenant être fait en utilisant ' Auto-layouting/Constraints '.

Les principaux avantages sont les suivants:

  1. Vous n'avez pas besoin de définir des cadres par programme!
  2. Si c'est bien fait, vous n'avez pas besoin de vous préoccuper de la réinitialisation des cadres pour les changements d'orientation.
  3. De plus, les changements d'appareils ne doivent pas vous déranger (lire, pas besoin de coder séparément pour différentes tailles d'écran).

Quelques inconvénients:

  1. Non compatible avec les versions antérieures - fonctionne uniquement pour iOS 6 et supérieur.
  2. Vous devez vous familiariser (mais vous gagnerez du temps par la suite).

La chose la plus cool est que nous nous concentrons sur la déclaration d'une intention telle que:

  • Je veux que ces deux boutons soient de la même largeur; ou
  • J'ai besoin que cette vue soit centrée verticalement et qu'elle s'étende jusqu'à un maximum de 10 pts à partir de Edge of Superview; ou même,
  • Je veux que ce bouton/étiquette se redimensionne en fonction de l'étiquette qu'il affiche!

Ici est un tutoriel simple pour se familiariser avec la mise en page automatique.

Pour un plus de détails .

Cela prend du temps au début, mais il semble que cela en vaudra la peine.

5
codeburn

Dans UIKit, il y a des ajouts à la classe NSString pour obtenir, à partir d'un objet NSString donné, la taille qu'il prendra lorsqu'il sera restitué dans une police donnée.

Docs était ici . Maintenant, c'est ici sous Obsolète.

En bref, si vous y allez:

CGSize stringsize = [myString sizeWithFont:[UIFont systemFontOfSize:14]]; 
//or whatever font you're using
[button setFrame:CGRectMake(10,0,stringsize.width, stringsize.height)];

... vous aurez défini le cadre du bouton sur la hauteur et la largeur de la chaîne que vous restiturez.

Vous voudrez probablement expérimenter avec un espace tampon autour de cette taille CGSize, mais vous commencerez au bon endroit.

126
Dan Ray

La manière de faire ceci dans le code est:

[button sizeToFit];

Si vous sous-classez et souhaitez ajouter des règles supplémentaires, vous pouvez remplacer:

- (CGSize)sizeThatFits:(CGSize)size;
98
Daniel Wood

Si votre bouton a été créé avec Interface Builder et que vous modifiez le titre en code, vous pouvez procéder comme suit:

[self.button setTitle:@"Button Title" forState:UIControlStateNormal];
[self.button sizeToFit];
31
guptron

Swift:

La chose importante ici est when appellerez-vous la .sizeToFit(), elle devrait l'être après avoir défini le texte à afficher pour qu'il puisse lire la taille requise, si vous mettez le texte à jour ultérieurement, appelez ensuite ça encore.

var button = UIButton()
button.setTitle("Length of this text determines size", forState: UIControlState.Normal)
button.sizeToFit()
self.view.addSubview(button)
19
Juan Boero

Pour ce faire, utilisez autolayout, essayez de définir une contrainte de largeur variable:

Width Constraint

Vous devrez peut-être aussi ajuster votre Content Hugging Priority et Content Compression Resistance Priority pour obtenir les résultats dont vous avez besoin.


UILabel est complètement auto-dimensionnant automatiquement :

Ce UILabel est simplement configuré pour être centré sur l'écran (deux contraintes seulement, horizontal/vertical):

Il change les largeurs de manière totalement automatique:

Vous n'avez pas besoin de définir la largeur ou la hauteur - c'est totalement automatique.

enter image description here

enter image description here

Notez que les petits carrés jaunes sont simplement attachés ("espacement" de zéro). Ils se déplacent automatiquement lorsque UILabel redimensionne.

L'ajout d'une contrainte "> =" définit une largeur minimale pour UILabel:

enter image description here

16
Tad

Si vous souhaitez redimensionner le texte par opposition au bouton, vous pouvez utiliser ...

button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = .5;
// The .5 value means that I will let it go down to half the original font size 
// before the texts gets truncated

// note, if using anything pre ios6, you would use I think
button.titleLabel.minimumFontSize = 8;
14
Logan

sizeToFit ne fonctionne pas correctement. au lieu:

myButton.size = myButton.sizeThatFits(CGSize.zero)

vous pouvez aussi ajouter contentInset au bouton:

myButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 4, 8)

6
Hashem Aboonajmi

Simplement:

  1. Créez UIView comme enveloppe avec une disposition automatique des vues.
  2. Mettez UILabel à l'intérieur de cette enveloppe. Ajoutez des contraintes qui colleront votre étiquette sur les bords de l'emballage.
  3. Mettez UIButton dans votre wrapper, puis ajoutez simplement les mêmes contraintes que pour UILabel.
  4. Profitez de votre bouton autosized avec le texte.
5

J'ai quelques besoins supplémentaires liés à ce poste que sizeToFit ne résout pas. Je devais garder le bouton centré à son emplacement d'origine, quel que soit le texte. Je ne veux jamais non plus que le bouton soit plus grand que sa taille d'origine.

Donc, je mets en forme le bouton pour sa taille maximale, enregistre cette taille dans le contrôleur et utilise la méthode suivante pour redimensionner le bouton lorsque le texte change:

+ (void) sizeButtonToText:(UIButton *)button availableSize:(CGSize)availableSize padding:(UIEdgeInsets)padding {    

     CGRect boundsForText = button.frame;

    // Measures string
    CGSize stringSize = [button.titleLabel.text sizeWithFont:button.titleLabel.font];
    stringSize.width = MIN(stringSize.width + padding.left + padding.right, availableSize.width);

    // Center's location of button
    boundsForText.Origin.x += (boundsForText.size.width - stringSize.width) / 2;
    boundsForText.size.width = stringSize.width;
    [button setFrame:boundsForText];
 }
3
raider33

Swift 4.2

Dieu merci, ceci est résolu. Après avoir défini un texte sur le bouton, vous pouvez récupérer le paramètre intrinsicContentSize, qui correspond à la taille naturelle d’un UIView (le document officiel est ici ). Pour UIButton, vous pouvez l’utiliser comme ci-dessous.

button.intrinsicContentSize.width

Pour votre information, j'ai ajusté la largeur pour lui donner une apparence correcte.

button.frame = CGRect(fx: xOffset, y: 0.0, width: button.intrinsicContentSize.width + 18, height: 40)

Simulateur

boutons UIB avec intrinsicContentSize

Source: https://riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-based-on-its-text-and-font

1
nator333

Cette classe de boutons à autoréglage en hauteur pour le texte (pour Xamarin mais peut être réécrite pour une autre langue)

[Register(nameof(ResizableButton))]
public class ResizableButton : UIButton
{
    NSLayoutConstraint _heightConstraint;
    public bool NeedsUpdateHeightConstraint { get; private set; } = true;

    public ResizableButton(){}

    public ResizableButton(UIButtonType type) : base(type){}

    public ResizableButton(NSCoder coder) : base(coder){}

    public ResizableButton(CGRect frame) : base(frame){}

    protected ResizableButton(NSObjectFlag t) : base(t){}

    protected internal ResizableButton(IntPtr handle) : base(handle){}

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        UpdateHeightConstraint();
        InvalidateIntrinsicContentSize();
    }

    public override void SetTitle(string title, UIControlState forState)
    {
        NeedsUpdateHeightConstraint = true;
        base.SetTitle(title, forState);
    }

    private void UpdateHeightConstraint()
    {
        if (!NeedsUpdateHeightConstraint)
            return;
        NeedsUpdateHeightConstraint = false;
        var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));

        var rect = new CGRect(Frame.X, Frame.Y, Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);

        if (_heightConstraint != null)
            RemoveConstraint(_heightConstraint);

        _heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, rect.Height);
        AddConstraint(_heightConstraint);
    }

     public override CGSize IntrinsicContentSize
     {
         get
         {
             var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));
             return new CGSize(Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);
         }
     }
}
1
elamaunt