web-dev-qa-db-fra.com

Autolayout - la taille intrinsèque d'UIButton n'inclut pas les encarts de titre

Si j'ai un UIButton arrangé à l'aide de l'autolayout, sa taille s'adapte bien à son contenu.

Si je définis une image en tant que button.image, la taille de l'instruction semble à nouveau tenir compte de cela.

Cependant, si je modifie la titleEdgeInsets du bouton, la présentation n'en tient pas compte et tronque le titre du bouton.

Comment puis-je m'assurer que la largeur intrinsèque du bouton représente l'insert?

enter image description here

Modifier:

J'utilise les éléments suivants:

[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

Le but est d’ajouter une séparation entre l’image et le texte.

156
Ben Packard

Vous pouvez résoudre ce problème sans avoir à remplacer des méthodes ou à définir une contrainte de largeur arbitraire. Vous pouvez tout faire dans Interface Builder comme suit.

  • La largeur du bouton intrinsèque est dérivée de la largeur du titre, de la largeur de l’icône et des incrustations gauche et droite content Edge.

  • Si un bouton contient à la fois une image et du texte, ils sont centrés en tant que groupe, sans marge entre les deux.

  • Si vous ajoutez un élément de contenu à gauche, il est calculé par rapport au texte et non au texte + icône.

  • Si vous définissez une image négative à gauche, l'image est tirée vers la gauche, mais la largeur globale du bouton n'est pas affectée.

  • Si vous définissez un encadré d'image négatif à gauche, la disposition actuelle utilise la moitié de cette valeur. Par conséquent, pour obtenir un incrément gauche de -20 points, vous devez utiliser une valeur d’insert gauche de -40 points dans Interface Builder.

Ainsi, vous fournissez un encart de contenu gauche assez grand pour créer un espace pour l'insertion gauche souhaitée et le remplissage intérieur entre l'icône et le texte, puis vous déplacez l'icône vers la gauche en doublant la quantité de remplissage souhaité entre l'icône et le texte. Le résultat est un bouton avec des insertions de contenu égales à gauche et à droite, ainsi qu'un texte et une paire d'icônes centrés en tant que groupe, avec une quantité spécifique de bourrage entre eux.

Quelques exemples de valeurs:

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)
151
jaredsinclair

Vous pouvez faire en sorte que cela fonctionne dans Interface Builder (sans écrire de code), en combinant des éléments de titre et de contenu négatifs et positifs. 

enter image description here

Update : Xcode 7 présente un bogue empêchant la saisie de valeurs négatives dans le champ Encodage Right, mais vous pouvez utiliser le contrôle pas à pas situé à côté pour réduire la valeur. (Merci Stuart)

Cela augmentera l'espacement de 8pt entre l'image et le titre et augmentera d'autant la largeur intrinsèque du bouton. Comme ça:

enter image description here

177
n.Drake

Pourquoi ne pas substituer la méthode intrinsicContentSize sur UIView? Par exemple:

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
                      s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}

Cela devrait indiquer au système de rappel automatique qu'il doit augmenter la taille du bouton pour permettre les incrustations et afficher le texte intégral. Je ne suis pas chez moi, je n'ai donc pas testé cela.

91
Maarten

Vous n'avez pas précisé comment vous définissez les incrustations. Je suppose donc que vous utilisez titleEdgeInsets, car je vois le même effet. Si j'utilise contentEdgeInsets à la place, cela fonctionne correctement.

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}
83
rdelmar

Ce fil est un peu vieux, mais je l’ai moi-même rencontré et j’ai pu le résoudre en utilisant un encart négatif. Par exemple, remplacez les valeurs de remplissage souhaitées ici:

UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
                                            -desiredRightPadding,
                                            -desiredTopPadding,
                                            -desiredLeftPadding);

Combiné aux bonnes contraintes de retrait automatique, vous vous retrouvez avec un bouton de redimensionnement automatique qui contient une image et du texte! Vu ci-dessous avec desiredLeftPadding défini sur 10.

Button with image and short text

Button with image and long text

Vous pouvez voir que le cadre du bouton n'englobe pas l'étiquette (puisque l'étiquette est décalée de 10 points vers la droite, en dehors des limites), mais que nous avons atteint 10 points de marge entre le texte et l'image.

18
Brian Gerstle

Et pour Swift a travaillé ceci:

extension UIButton {
    override open var intrinsicContentSize: CGSize {
        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}

Love U Swift

18
pegpeg

Pour Swift 3 basé sur la réponse de pegpeg :

extension UIButton {

    override open var intrinsicContentSize: CGSize {

        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)

    }

}
7
TheoK

Tout ce qui précède n'a pas fonctionné pour iOS 9+, ce que j'ai fait est:

  • Ajouter une contrainte de largeur (pour une largeur minimale lorsque le bouton ne contient pas de texte. Le bouton sera automatiquement redimensionné si du texte est fourni)
  • définir la relation à Supérieur ou égal

 enter image description here

Maintenant, pour ajouter une bordure autour du bouton, utilisez simplement la méthode suivante:

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
6
Oritm

Je voulais ajouter un espace de 5 pt entre l'icône de mon UIButton et l'étiquette. Voici comment je l'ai réalisé:

UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);

La façon dont contentEdgeInsets, titleEdgeInsets et imageEdgeInsets se rapportent les uns aux autres nécessite un peu de va-et-vient entre chaque insertion. Donc, si vous ajoutez des encarts à la gauche du titre, vous devez ajouter un encadré négatif à droite et laisser plus d'espace (via un encadré positif) sur le contenu à droite.

En ajoutant un encadré de contenu correspondant au décalage des encarts de titre, mon texte ne dépasse pas les limites du bouton.

3
orj

L'option est également disponible dans le générateur d'interface. Voir l'encart. Je mets à gauche et à droite à 3. Fonctionne comme un charme. 

Interface builder screenshot

3
zeiteisen

La solution que j'utilise consiste à ajouter une contrainte de largeur sur le bouton. Puis quelque part dans l'initialisation, une fois votre texte défini, mettez à jour la contrainte de largeur de la manière suivante:

self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;

Où 8 est ce que votre encart est.

1
Bob Spryn

l'appel de sizeToFit () permet de s'assurer que contentEdgeInset est pris en compte

 extension UIButton {

              open override func draw(_ rect: CGRect) { 
                    self.contentEdgeInsets = UIEdgeInsets(top: 10,left: 40,bottom: 10,right: 40)
                    self.sizeToFit()
              }
           }
0
Ali