181 votes

Étiquette sous l'image dans UIButton

J'essaie de créer un bouton avec du texte sous l'icône (un peu comme les boutons des applications), mais cela semble difficile à réaliser. Avez-vous une idée de la manière dont je peux faire en sorte que le texte s'affiche ? en dessous de l'image avec un UIButton ?

0 votes

Il est assez facile et faisable de créer une sous-classe personnalisée de UIbutton contenant une UIImage et une UILabel, positionnée comme vous auriez besoin...

7 votes

Ou utilisez simplement un UIButton et un UILabel.

0 votes

Pour contrôler précisément la taille et la mise en page automatique, vous pouvez essayer ceci : https://github.com/albert-zhang/AZCenterLabelButton ( Lien )

132voto

reecon Points 8418

Ou vous pouvez simplement utiliser cette catégorie :

ObjC

@interface UIButton (VerticalLayout)

- (void)centerVerticallyWithPadding:(float)padding;
- (void)centerVertically;

@end

@implementation UIButton (VerticalLayout)

- (void)centerVerticallyWithPadding:(float)padding {
    CGSize imageSize = self.imageView.frame.size;
    CGSize titleSize = self.titleLabel.frame.size;
    CGFloat totalHeight = (imageSize.height + titleSize.height + padding);

    self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height),
                                            0.0f,
                                            0.0f,
                                            - titleSize.width);

    self.titleEdgeInsets = UIEdgeInsetsMake(0.0f,
                                            - imageSize.width,
                                            - (totalHeight - titleSize.height),
                                            0.0f);

    self.contentEdgeInsets = UIEdgeInsetsMake(0.0f,
                                              0.0f,
                                              titleSize.height,
                                              0.0f);
}

- (void)centerVertically {
    const CGFloat kDefaultPadding = 6.0f;
    [self centerVerticallyWithPadding:kDefaultPadding];
}

@end

Extension rapide

extension UIButton {

    func centerVertically(padding: CGFloat = 6.0) {
        guard
            let imageViewSize = self.imageView?.frame.size,
            let titleLabelSize = self.titleLabel?.frame.size else {
            return
        }

        let totalHeight = imageViewSize.height + titleLabelSize.height + padding

        self.imageEdgeInsets = UIEdgeInsets(
            top: -(totalHeight - imageViewSize.height),
            left: 0.0,
            bottom: 0.0,
            right: -titleLabelSize.width
        )

        self.titleEdgeInsets = UIEdgeInsets(
            top: 0.0,
            left: -imageViewSize.width,
            bottom: -(totalHeight - titleLabelSize.height),
            right: 0.0
        )

        self.contentEdgeInsets = UIEdgeInsets(
            top: 0.0,
            left: 0.0,
            bottom: titleLabelSize.height,
            right: 0.0
        )
    }

}

Suggestion : Si la hauteur du bouton est inférieure à totalHeight l'image sera dessinée en dehors des frontières.

imageEdgeInset.top devrait être :

max(0, -(totalHeight - imageViewSize.height))

6 votes

Je pense que c'est la meilleure réponse puisqu'elle utilise edgeInsets au lieu d'ajuster manuellement le cadre. Elle fonctionne également très bien avec la mise en page automatique lorsqu'elle est appelée à partir de layoutSubviews dans la vue supérieure du bouton. La seule suggestion est d'utiliser CGRectGetHeight() y CGRectGetWidth() lors de la récupération de la hauteur et de la largeur de l'imageView et du titleLabel.

2 votes

Lorsque je l'utilise, l'image apparaît au-dessus de la vue du bouton. Pour la centrer, dois-je CGFloat inset = (self.frame.size.height - totalHeight)/2; self.contentEdgeInsets = UIEdgeInsetsMake(inset, 0.0f, inset, 0.0f);

15 votes

L'extension Swift ne l'a pas mis en page correctement pour moi.

93voto

Chris Points 2012

Dans Xcode, vous pouvez simplement définir l'Insertion gauche du titre du bord à la largeur négative de l'image. Cela permettra d'afficher l'étiquette au centre de l'image.

Pour que l'étiquette s'affiche sous l'image (un peu comme les boutons de l'application), vous devrez peut-être définir le paramètre Edge Title Top Inset sur un nombre positif.

Edit : Voici du code pour réaliser cela sans utiliser Interface Builder :

/// This will move the TitleLabel text of a UIButton to below it's Image and Centered.
/// Note: No point in calling this function before autolayout lays things out.
/// - Parameter padding: Some extra padding to be applied
func centerVertically(padding: CGFloat = 18.0) {
    // No point in doing anything if we don't have an imageView size
    guard let imageFrame = imageView?.frame else { return }
    titleLabel?.numberOfLines = 0
    titleEdgeInsets.left = -(imageFrame.width + padding)
    titleEdgeInsets.top = (imageFrame.height + padding)
}

Veuillez noter que cela ne fonctionnera pas si vous utilisez autolayout et que le bouton n'a pas encore été disposé dans l'écran via les contraintes.

1 votes

C'est la façon de faire... à moins que vous ne fassiez cela à plusieurs reprises avec un certain nombre de boutons (de tailles différentes)... dans ce cas, j'ai obtenu de bons résultats avec une version modifiée de la solution d'Erik W.

5 votes

Juste pour être sûr que les gens réalisent ça. La valeur doit être la largeur négative de l'image, même si le bouton est plus large que la largeur de l'image.

1 votes

Cela n'a pas fonctionné pour moi. Mon texte apparaît toujours à droite de l'image, c'est-à-dire qu'il ne s'enroule pas sous celle-ci.

33voto

Dave Batton Points 2024

Sous-classe UIButton . Annulation - layoutSubviews pour déplacer l'intégré subviews dans de nouvelles positions :

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGRect frame = self.imageView.frame;
    frame = CGRectMake(truncf((self.bounds.size.width - frame.size.width) / 2), 0.0f, frame.size.width, frame.size.height);
    self.imageView.frame = frame;

    frame = self.titleLabel.frame;
    frame = CGRectMake(truncf((self.bounds.size.width - frame.size.width) / 2), self.bounds.size.height - frame.size.height, frame.size.width, frame.size.height);
    self.titleLabel.frame = frame;
}

0 votes

Personnellement, j'ai dû définir la valeur y de titleLabel à 0 et la hauteur à la hauteur du cadre pour que le texte s'affiche avec l'image. Cela n'a pas de sens pour moi, mais cela fonctionne... même si je suis encore en train d'apprendre la manière "Apple" de configurer les contrôles.

6 votes

En fait, le meilleur moyen est de remplacer titleRectForContentRect y imageRectForContentRect

17voto

Erik W Points 540

Si vous sous-classez UIButton y override layoutSubviews vous pouvez utiliser la fonction ci-dessous pour centrer l'image et placer le titre en dessous :

kTextTopPadding est une constante que vous devrez introduire et qui détermine l'espace entre l'image et le texte situé en dessous.

-(void)layoutSubviews {
    [super layoutSubviews];

    // Move the image to the top and center it horizontally
    CGRect imageFrame = self.imageView.frame;
    imageFrame.origin.y = 0;
    imageFrame.origin.x = (self.frame.size.width / 2) - (imageFrame.size.width / 2);
    self.imageView.frame = imageFrame;

    // Adjust the label size to fit the text, and move it below the image
    CGRect titleLabelFrame = self.titleLabel.frame;
    CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font
                                        constrainedToSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)
                                        lineBreakMode:NSLineBreakByWordWrapping];
    titleLabelFrame.size.width = labelSize.width;
    titleLabelFrame.size.height = labelSize.height;
    titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2);
    titleLabelFrame.origin.y = self.imageView.frame.origin.y + self.imageView.frame.size.height + kTextTopPadding;
    self.titleLabel.frame = titleLabelFrame;

}

16voto

Kenny Winker Points 6171

Ceci est une version modifiée de l'excellente réponse d'Erik W. Mais au lieu de placer l'image centrée en HAUT de la vue, elle place l'image et l'étiquette centrées dans la vue comme un groupe.

La différence est :

+-----------+
|    ( )    |
|   Hello   |     // Erik W's code
|           |
|           |
+-----------+

vs

+-----------+
|           |
|    ( )    |     // My modified version
|   Hello   |
|           |
+-----------+

Source ci-dessous :

-(void)layoutSubviews {
    [super layoutSubviews];

    CGRect titleLabelFrame = self.titleLabel.frame;
    CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];

    CGRect imageFrame = self.imageView.frame;

    CGSize fitBoxSize = (CGSize){.height = labelSize.height + kTextTopPadding +  imageFrame.size.height, .width = MAX(imageFrame.size.width, labelSize.width)};

    CGRect fitBoxRect = CGRectInset(self.bounds, (self.bounds.size.width - fitBoxSize.width)/2, (self.bounds.size.height - fitBoxSize.height)/2);

    imageFrame.origin.y = fitBoxRect.origin.y;
    imageFrame.origin.x = CGRectGetMidX(fitBoxRect) - (imageFrame.size.width/2);
    self.imageView.frame = imageFrame;

    // Adjust the label size to fit the text, and move it below the image

    titleLabelFrame.size.width = labelSize.width;
    titleLabelFrame.size.height = labelSize.height;
    titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2);
    titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding;
    self.titleLabel.frame = titleLabelFrame;
}

FYI : Ceci peut être cassé lorsqu'il est combiné avec des animations UIView, car layoutSubviews est appelé pendant celles-ci.

0 votes

La ligne qui calcule le labelSize ne devrait-elle pas utiliser self.bounds.size.width au lieu de self.frame.size.width ?

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