redimensionner l'image dans un UIButton en AspectFit?

94

Je veux ajouter une image à un UIButton, et je veux également redimensionner mon image pour l'adapter à l'UIButton (réduire l'image). Veuillez me montrer comment faire.

C'est ce que j'ai essayé, mais cela ne fonctionne pas:

  • Ajout d'une image au bouton et utilisation setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Créer une "image étirée":
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];
KONG
la source
Je pense que cela a été changé pour être le comportement par défaut dans le firmware 4.0 et plus.
Shaun Budhram
1
Voir stackoverflow.com/a/28205566/481207 pour la solution.
Matt

Réponses:

28

Si vous voulez vraiment mettre à l'échelle une image, faites-le, mais vous devez la redimensionner avant de l'utiliser. Le redimensionner au moment de l'exécution perdra simplement des cycles CPU.

Voici la catégorie que j'utilise pour redimensionner une image:

UIImage + Extra.h

@interface UIImage (Extras)
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
@end;

UIImage + Extra.m

@implementation UIImage (Extras)

- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {

UIImage *sourceImage = self;
UIImage *newImage = nil;

CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;

CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;

CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;

CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

if (!CGSizeEqualToSize(imageSize, targetSize)) {

        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor < heightFactor) 
                scaleFactor = widthFactor;
        else
                scaleFactor = heightFactor;

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image

        if (widthFactor < heightFactor) {
                thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
        } else if (widthFactor > heightFactor) {
                thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
}


// this is actually the interesting part:

UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0);

CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width  = scaledWidth;
thumbnailRect.size.height = scaledHeight;

[sourceImage drawInRect:thumbnailRect];

newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

if(newImage == nil) NSLog(@"could not scale image");


return newImage ;
}

@end

Vous pouvez l'utiliser à la taille souhaitée. Comme :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];
gcamp
la source
Merci pour votre réponse, Gcamp. J'avais une méthode pour redimensionner par rapport. Mais j'essaie toujours de trouver un moyen de dire à UIButton de le faire pour moi. Mon image est chargée depuis Internet, je ne peux donc pas la redimensionner au moment de la compilation. BTW, merci beaucoup pour votre réponse.
KONG
2
Étant donné que l'image est placée dans un CALayer, rendue et mise en cache par Quartz, les performances ne devraient pas être pires si vous la placez à sa taille réelle. Dans tous les cas, vous redimensionnez ~ 1 fois. La réponse de gcamp est beaucoup plus importante si vous redimensionnez constamment le bouton ou si vous faites d'autres choses qui inciteraient Quartz à redessiner le calque d'image.
Ben Gotow
il semble que la qualité de l'image soit réduite. je teste sur l'iphone 6 plus. Est-ce vrai? J'ai aussi une image 3x.
Khant Thu Linn
Oui, ce code est assez ancien. C'était UIGraphicsBeginImageContextau lieu de UIGraphicsBeginImageContextWithOptions. Je viens de le réparer.
gcamp
oui mais dans de nombreux cas, peu importe si vous perdez quelques cycles, donc inutile de remplir le bélier
Radu Simionescu
203

J'ai eu le même problème. Définissez simplement le ContentMode de ImageView qui se trouve à l'intérieur de l'UIButton.

[[self.itemImageButton imageView] setContentMode: UIViewContentModeScaleAspectFit];
[self.itemImageButton setImage:[UIImage imageNamed:stretchImage] forState:UIControlStateNormal];

J'espère que cela t'aides.

Dave
la source
14
Assurez-vous de définir l' imageView . Je n'ai pas non plus remarqué, pendant un moment, que j'utilisais toujours backgroundImageView et que cela ne fonctionnait pas pour cela.
Alexandre Gomes
2
Il semble que cette méthode pose quelques problèmes lorsque l'état du bouton est «mis en évidence». L'image reviendra au mode de remplissage. Une idée?
Yuanfei Zhu
Cela ne fonctionne pas pour moi. Cependant, je le fais fonctionner en utilisant [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stretchImage] forState: UIControlStateNormal];
Mickey
3
Cela a fonctionné pour moi. J'ai défini le mode de contenu comme ci-dessus. Cependant, vous devez également définir la même image de l'état en surbrillance afin d'éviter que l'image ne retourne en "mode remplissage". Par exemple, [imageButton setImage: image forState: UIControlStateHighlighted];
Christopher
1
Vous pouvez le faire dans Interface Builder avec le chemin d'accès imageView.contentMode, le type Numberet la valeur de la 1
clé
107

Aucune des réponses ici n'a vraiment fonctionné pour moi, j'ai résolu le problème avec le code suivant:

button.contentMode = UIViewContentModeScaleToFill;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;

Vous pouvez également le faire dans Interface Builder.

entrez la description de l'image ici

nalexn
la source
5
Cela ne vous donne pas le comportement d' ajustement d'aspect comme demandé par l'OP.
Ortwin Gentz
3
@OrtwinGentz ​​vous pouvez sélectionner le mode et définir à la Aspect fitplace de scale to fill.
Daniel
55

Le moyen le plus simple de définir par programme une imageView UIButton en mode d' ajustement de l'aspect :

Rapide

button.contentHorizontalAlignment = .fill
button.contentVerticalAlignment = .fill
button.imageView?.contentMode = .scaleAspectFit

Objectif c

button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
button.imageView.contentMode = UIViewContentModeScaleAspectFit;

Remarque: vous pouvez changer .scaleAspectFit (UIViewContentModeScaleAspectFit) en .scaleAspectFill (UIViewContentModeScaleAspectFill) pour définir un mode de remplissage d'aspect

Tanguy G.
la source
20

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
16

Cela peut maintenant être fait via les propriétés UIButton d'IB. La clé est de définir votre image comme arrière-plan, sinon cela ne fonctionnera pas.

entrez la description de l'image ici

capikaw
la source
14

En développant la réponse de Dave, vous pouvez définir tous contentModeles boutons imageViewdans IB, sans aucun code, en utilisant les attributs d'exécution:

entrez la description de l'image ici

  • 1signifie UIViewContentModeScaleAspectFit,
  • 2signifierait UIViewContentModeScaleAspectFill.
Ortwin Gentz
la source
8

Si vous souhaitez simplement réduire l'image de votre bouton:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
Tulleb
la source
Cela devrait être yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
sdsykes
Je n'ai pas essayé avec .imageView. Cela fonctionne sans assez bien.
Tulleb
5

1 - Effacer le texte par défaut du bouton (important)

2 - définir l'alignement comme l'image

3 - définir le mode de contenu comme l'image

entrez la description de l'image ici

Hamid Reza Ansari
la source
Bonne réponse frérot ... m'a beaucoup aidé. Merci!
BharathRao
5

J'ai une méthode qui le fait pour moi. La méthode prend UIButtonet adapte l'aspect de l'image.

-(void)makeImageAspectFitForButton:(UIButton*)button{
    button.imageView.contentMode=UIViewContentModeScaleAspectFit;
    button.contentHorizontalAlignment=UIControlContentHorizontalAlignmentFill;
    button.contentVerticalAlignment=UIControlContentVerticalAlignmentFill;
}
Abedalkareem Omreyh
la source
4

La solution la plus propre consiste à utiliser la mise en page automatique . J'ai abaissé la priorité de résistance à la compression du contenu de mon UIButtonet défini l'image (pas l'image d' arrière-plan ) via Interface Builder . Après cela, j'ai ajouté quelques contraintes qui définissent la taille de mon bouton (assez complexe dans mon cas) et cela a fonctionné comme un charme.

Rudolf Adamkovič
la source
Cela a fonctionné pour moi - mais seulement si j'ai choisi d'utiliser «l'image d'arrière-plan», pas l'image réelle. Tout ce qui fonctionne! Cela me poussait NUTS.
Andy
Sous Xcode 6.2 cela a fonctionné pour moi mais comme @AndrewHeinlein l'a dit, utiliséBackground Image
RoLYroLLs
3

assurez-vous que vous avez défini l'image sur la propriété Image, mais pas sur l'arrière-plan

Andrew
la source
2

L'image d'arrière-plan peut en fait être définie pour mettre à l'échelle le remplissage d'aspect assez facilement. Juste besoin de faire quelque chose comme ça dans une sous-classe de UIButton:

- (CGRect)backgroundRectForBounds:(CGRect)bounds
{
    // you'll need the original size of the image, you 
    // can save it from setBackgroundImage:forControlState
    return CGRectFitToFillRect(__original_image_frame_size__, bounds);
}

// Utility function, can be saved elsewhere
CGRect CGRectFitToFillRect( CGRect inRect, CGRect maxRect )
{
    CGFloat origRes = inRect.size.width / inRect.size.height;
    CGFloat newRes = maxRect.size.width / maxRect.size.height;

    CGRect retRect = maxRect;

    if (newRes < origRes)
    {
        retRect.size.width = inRect.size.width * maxRect.size.height / inRect.size.height;
        retRect.origin.x = roundf((maxRect.size.width - retRect.size.width) / 2);
    }
    else
    {
        retRect.size.height = inRect.size.height * maxRect.size.width / inRect.size.width;
        retRect.origin.y = roundf((maxRect.size.height - retRect.size.height) / 2);
    }

    return retRect;
}
Andy Poes
la source
N'est-ce pas possible sans sous-classe?
Iulian Onofrei
Cette réponse était spécifiquement pour backgroundImage. Pour l'image principale, vous pouvez singe avec le imageEdgeInsets.
Andy Poes
Je sais, et je voulais s'il est possible d'y parvenir sans sous-classe.
Iulian Onofrei
Autant que je sache, vous ne pouvez pas ajuster le backgroundImage sans sous-classer.
Andy Poes
1

Swift 5.0

 myButton2.contentMode = .scaleAspectFit
 myButton2.contentHorizontalAlignment = .fill
 myButton2.contentVerticalAlignment = .fill
Qasim Mirza
la source
0

Pour Xamarin.iOS (C #):

    myButton.VerticalAlignment = UIControlContentVerticalAlignment.Fill;
    myButton.HorizontalAlignment = UIControlContentHorizontalAlignment.Fill;
    myButton.ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;
Maciej
la source
-1

Il vous suffit de définir le mode de contenu de UIButton imageview pour trois événements. -

[cell.button setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];

[cell.button setImage:[UIImage imageWithData:data] forState:UIControlStateHighlighted];

[cell.imgIcon setImage:[UIImage imageWithData:data] forState:UIControlStateSelected];

Nous avons le code pour trois événements bcoz tout en mettant en évidence ou en sélectionnant si la taille du bouton est CARRÉE et la taille de l'image est un rectangle, alors il affichera une image carrée au moment de la mise en évidence ou de la sélection.

Je suis sûr que cela fonctionnera pour vous.

ruyamonis346
la source
Vous ne définissez pas un mode de contenu, vous définissez l'image. Et ce ne sont pas des événements, ce sont des états. Vous faites un gros gâchis. Cela n'a aucun rapport avec la question.
manecosta