UIButton n'ira pas à Aspect Fit sur iPhone

105

J'ai quelques UIButtons, et dans IB, ils sont réglés sur Aspect Fit, mais pour une raison quelconque, ils s'étirent toujours. Y a-t-il autre chose que vous devez définir? J'ai essayé tous les différents modes d'affichage et aucun d'eux ne fonctionne, ils s'étirent tous.

Marty
la source
La réponse de @Werner Altesischer est la bonne. Apportez les modifications appropriées.
Harshit Gupta
1
@marty Définissez-vous l'image ou l'image d'arrière-plan? l'image d'arrière-plan ne le prend pas en charge, seule l'image.
Juan Boero

Réponses:

45

J'ai déjà eu ce problème. Je l'ai résolu en plaçant mon image dans un UIImageView, où les contentModeparamètres fonctionnent réellement, et en mettant une personnalisation transparente UIButtonpar-dessus cela.

EDIT: Cette réponse est obsolète. Voir la réponse de @Werner Altewischer pour la réponse correcte dans les versions modernes d'iOS.

Dan Ray
la source
Ouais a essayé ça, mais maintenant
je
Comment gérez-vous les états des boutons avec cette technique? On dirait que répondre à une interaction de l'utilisateur comme «surligné» serait un cauchemar.
SooDesuNe
3
Cela aurait peut-être été la bonne façon de le faire il y a 2,5 ans, lorsque cette question a été répondue, mais vous pouvez maintenant modifier l'ImageView interne de l'UIButton et y définir le mode de contenu. Voir la réponse de @Werner Altewischer
Steve Haley
233

La solution consiste à définir le contentModesur la imageViewpropriété du UIButton. Le UIButtondoit être créé avec un type personnalisé pour que cela fonctionne, je crois (sinon, il nilest retourné pour cette propriété).

Werner Altewischer
la source
67
Cela a fonctionné pour moi:[button.imageView setContentMode:UIViewContentModeScaleAspectFit];
ayreguitar
2
Cela fonctionne aussi pour moi, mais si je règle ajustsImageWhenHighlighted = YES, l'image est à nouveau étirée lorsque je tape sur le bouton.
cduck
1
L'étirement dans ajustsImage a été éliminé dans iOS 6.
Ben Flynn
3
Dans iOS 8, cela ne fonctionne pas pour moi. La réponse originale (en plaçant une imageView derrière un bouton transparent) fonctionne mieux.
user1416564
3
à Swift du jour:button.imageView!.contentMode = UIViewContentMode.scaleAspectFit
Nestor
57

Cette méthode a très bien fonctionné pour moi:

Dans Xib, sélectionnez le bouton et réglez user defined runtime attributes:

  • Chemin clé: self.imageView.contentMode
  • Type: Number
  • Valeur: 1

Cliquez ici pour voir plus clairement la solution

Nous utilisons number parce que vous ne pouvez pas utiliser enum ici. Mais UIViewContentModeScaleAspectFit est égal à 1.

István Stefánovics
la source
2
Cela a également mis à jour l'image dans le générateur d'interface pendant la conception. Excellente solution.
George Filippakos
Excellente solution, peu de code et fonctionne comme un charme, l'énumération est basée sur des éléments de liste en mode contenu.
Kross le
Vous pouvez également ajouter une extension pour le rendre un peu plus facile: extension UIButton { @IBInspectable var imageContentMode: Int { get {return imageView?.contentMode.rawValue ?? 0} set {imageView?.contentMode = UIViewContentMode(rawValue: newValue) ?? .scaleAspectFit} } }
Yonat
Sans «moi» a imageView.contentModetravaillé pour moi!
parJeevan
22

Si vous faites cela dans Interface Builder, vous pouvez utiliser l'inspecteur d'attributs d'exécution pour le définir directement sans aucun code.

Définissez votre chemin de clé sur le bouton pour qu'il soit "imageView.contentMode" avec un type de "Number" et une valeur de "1" (ou le mode de votre choix).

imageview.contentMode = 1

averydev
la source
14

Utilisez l'imageView du bouton pour contentMode. Pas directement sur le bouton lui-même.

homeButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
homeButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
homeButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
[homeButton setImage:[UIImage imageNamed:kPNGLogo] forState:UIControlStateNormal];
Ahmed Elashker
la source
6

Si vous placez l'image dans un UIImageViewderrière le bouton, vous perdrez la fonctionnalité intégrée de la UIButtonclasse, telle que adjustsImageWhenHighlightedet adjustsImageWhenDisabled, et bien sûr la possibilité de définir différentes images pour différents états (sans avoir à le faire vous-même).

Si nous voulons avoir une image non étirée pour tous les états de contrôle , une approche consiste à obtenir l'image en utilisant imageWithCGImage:scale:orientation, comme dans la méthode suivante:

- (UIImage *) getScaledImage:(UIImage *)img insideButton:(UIButton *)btn {

    // Check which dimension (width or height) to pay respect to and
    // calculate the scale factor
    CGFloat imgRatio = img.size.width / img.size.height, 
            btnRatio = btn.frame.size.width / btn.frame.size.height,
            scaleFactor = (imgRatio > btnRatio 
                           ? img.size.width / btn.frame.size.width
                           : img.size.height / btn.frame.size.height;

    // Create image using scale factor
    UIImage *scaledImg = [UIImage imageWithCGImage:[img CGImage]
                                             scale:scaleFactor
                                       orientation:UIImageOrientationUp];
    return scaledImg;
}

Pour implémenter cela, nous écririons:

UIImage *scaledImg = [self getScaledImage:myBtnImg insideButton:myBtn];
[myBtn setImage:scaledImg forState:UIControlStateNormal];

Cela devrait empêcher l'image de s'étirer dans tous les états de contrôle. Cela a fonctionné pour moi, mais faites-moi savoir si ce n'est pas le cas!

REMARQUE: Ici, nous abordons un problème lié à UIButton, mais le insideButton:pourrait aussi bien être insideView:, ou à tout ce que l'on souhaite insérer dans l'image.

Alexandre Wallin
la source
6

J'ai eu ce problème il y a quelque temps. Le problème que j'ai eu était que j'essayais d'appliquer cet effet à l'UIButton d'arrière-plan qui est limité et signifie donc que vous ne pouvez pas l'ajuster aussi facilement.

L'astuce est de la définir comme une image, puis d'appliquer la technique de @ ayreguitar et cela devrait résoudre le problème!

UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myButton setContentMode:UIViewContentModeScaleAspectFill];
[myButton setImage:@"myImage.png" forState:UIControlStateNormal];
Joe Barbour
la source
4

Cela a fonctionné pour moi

[button.imageView setContentMode:UIViewContentModeScaleAspectFit];

Merci à @ayreguitar pour son commentaire

Karan Alangat
la source
4

Voici une réponse alternative rapide:

myButton.imageView?.contentMode = .ScaleAspectFit
João Neves
la source
4

En combinant plusieurs réponses différentes en une seule solution: créez un bouton avec un type personnalisé, définissez la propriété imageView contentMode du bouton et définissez l'image du bouton (pas l'image d'arrière-plan, qui sera toujours mise à l'échelle pour remplir).

//Objective-C:
UIImage *image = [UIImage imageNamed:"myImageName.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;

//Swift:
let image = UIImage(named: "myImageName.png")
let button = UIButton(type: .custom)
button.imageView?.contentMode = .scaleAspectFit
button.setImage(image, for: .normal)
Escroc
la source
3
btn.imageView.contentMode = UIViewContentModeScaleAspectFit;
selaband
la source
Bien que cet extrait de code puisse résoudre la question, inclure une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. - De l'avis
Ferrybig
2

Cette réponse est basée sur la réponse de @ WernerAltewischer .

Pour éviter d'avoir connecté mon bouton à un IBOutlet pour exécuter le code dessus, j'ai sous-classé la classe d'UIButton:

// .h
@interface UIButtonWithImageAspectFit : UIButton
@end

// .m
@implementation UIButtonWithImageAspectFit

- (void) awakeFromNib {
    [self.imageView setContentMode:UIViewContentModeScaleAspectFit];
}

@end



Créez maintenant un bouton personnalisé dans votre xib et définissez son image (pas l'image d'arrière-plan):

UIButtonWithImageAspectFit: créer et définir une image


Ensuite, définissez sa classe:

UIButtonWithImageAspectFit: définir une classe personnalisée

Vous avez terminé!
Au lieu de
UIButton sans ajustement de l'aspect de l'image
l'ajustement de l'aspect de l'image de votre bouton est maintenant comme prévu:
UIButton avec ajustement de l'aspect de l'image

Guillaume
la source
2

ios 12. Vous devez également ajouter l'alignement du contenu

class FitButton: UIButton {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)


    }

    override func layoutSubviews() {
        self.imageView?.contentMode = .scaleAspectFill
        self.contentHorizontalAlignment = .fill
        self.contentVerticalAlignment = .fill
        super.layoutSubviews()


    }

}
João Nunes
la source
1

J'ai eu des problèmes avec l'image qui ne se redimensionnait pas proportionnellement, donc la façon dont je l'ai corrigée utilisait des encarts de bord.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
ninjaneer
la source
1

Les modes de contenu UIView s'appliquent au "contenu" du CALayer correspondant. Cela fonctionne pour les UIImageViews car ils définissent le CALayercontenu sur le fichier CGImage.

drawRect: rend finalement au contenu de la couche.

Une personnalisation UIButton(pour autant que je sache) n'a pas de contenu (les boutons de style rectangle arrondi peuvent être rendus à l'aide de contenu). Le bouton a des sous-vues: l'arrière-plan UIImageView, l'image UIImageViewet le titre UILabel. La définition de contentModesur les sous-vues peut faire ce que vous voulez, mais déranger la UIButtonhiérarchie des vues est un peu un non-non.

tc.
la source
1

Changer UIButton.imageView.contentModen'a pas fonctionné pour moi.
J'ai résolu le problème en définissant l'image sur la propriété «Arrière-plan».
Vous pouvez ajouter une contrainte de rapport si vous avez besoin

Parc Soohwan
la source
1

Cela recoupe de nombreuses autres réponses, mais la solution pour moi était de

  • régler le contentModedu UIImageViewpour le bouton .ScaleAspectFit- qui soit peut être fait dans le dans Interface Builder « définie par l' utilisateur d' exécution Attributs » (ie. self.imageView.contentMode, numéro 1) ou dans une UIButtonsous - classe;
  • désactiver "Autoresize Subviews";
  • définissez «Bord» sur «Image» et les valeurs «Haut» et «Bas» appropriées pour «Encart» (ce qui ne peut être nécessaire que si vous, comme moi, avez utilisé un PDF comme image).
Plindberg
la source
0

Vous pouvez utiliser imageWithCGImage comme indiqué ci-dessus (mais sans les parenthèses manquantes).

De plus ... des millions de téléphones non 4.0 ne fonctionneront pas du tout avec ce code.

Alice
la source
0

[button sizeToFit] travaillé pour moi.

Hila
la source
0

Similaire à @Guillaume, j'ai créé une sous-classe d'UIButton en tant que fichier Swift. Ensuite, définissez ma classe personnalisée dans Interface Builder:

constructeur d'interface.

Et voici le fichier Swift:

import UIKit

class TRAspectButton : UIButton {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.imageView?.contentMode = .ScaleAspectFit
    }
}
Motine
la source
-1

J'ai eu le même problème, mais je n'ai pas pu le faire fonctionner (c'est peut-être un bogue avec le SDK).

Finalement, comme solution de contournement, j'ai placé un UIImageViewderrière mon bouton et défini les options que je voulais, puis j'ai simplement placé un blanc UIButtondessus.

Anshu Chimala
la source
7
Est-ce qu'il y a un écho ici? ;-)
Dan Ray