Bild in einem UIButton auf AspectFit skalieren?

94

Ich möchte einem UIButton ein Bild hinzufügen und mein Bild auch so skalieren, dass es zum UIButton passt (Bild verkleinern). Bitte zeigen Sie mir, wie es geht.

Das habe ich versucht, aber es funktioniert nicht:

  • Hinzufügen eines Bildes zur Schaltfläche und Verwenden von setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Erstellen eines "Stretch-Bildes":
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];
KONG
quelle
Ich denke, dies wurde geändert, um das Standardverhalten in Firmware 4.0 und höher zu sein.
Shaun Budhram
1
Die Lösung finden Sie unter stackoverflow.com/a/28205566/481207 .
Matt

Antworten:

28

Wenn Sie ein Bild wirklich skalieren möchten, tun Sie dies, aber Sie sollten die Größe ändern, bevor Sie es verwenden. Wenn Sie die Größe zur Laufzeit ändern, gehen nur die CPU-Zyklen verloren.

Dies ist die Kategorie, mit der ich ein Bild skaliere:

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

Sie können es in der gewünschten Größe verwenden. Mögen :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];
gcamp
quelle
Danke für deine Antwort, Gcamp. Ich hatte eine Methode zur Größenänderung nach Verhältnis. Aber ich versuche immer noch, UIButton zu sagen, dass er es für mich tun soll. Mein Bild wird aus dem Internet geladen, daher kann ich die Größe beim Kompilieren nicht ändern. Übrigens, vielen Dank für Ihre Antwort.
KONG
2
Da das Bild in einem CALayer abgelegt, gerendert und von Quartz zwischengespeichert wird, sollte die Leistung nicht schlechter sein, wenn Sie es in voller Größe dort ablegen. In beiden Fällen ändern Sie die Größe ~ 1 Mal. Die Antwort von gcamp ist viel wichtiger, wenn Sie die Größe der Schaltfläche ständig ändern oder andere Dinge tun, die Quartz veranlassen würden, die Bildebene neu zu zeichnen.
Ben Gotow
Es scheint, als ob die Bildqualität verringert ist. Ich teste auf dem iPhone 6 Plus. Ist es wahr? Ich habe auch 3x Bild.
Khant Thu Linn
Ja, dieser Code ist ziemlich alt. Es war UIGraphicsBeginImageContextstatt UIGraphicsBeginImageContextWithOptions. Habe es einfach behoben.
Gcamp
Ja, aber in vielen Fällen spielt es keine Rolle, ob Sie ein paar Zyklen verlieren, also macht es keinen Sinn, den Widder
aufzufüllen
203

Ich hatte das gleiche Problem. Legen Sie einfach den ContentMode der ImageView fest, die sich im UIButton befindet.

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

Hoffe das hilft.

Dave
quelle
14
Stellen Sie sicher, dass Sie die Bildansicht einstellen . Ich bemerkte auch ein wenig nicht, dass ich immer noch backgroundImageView verwendete und es dafür nicht funktionierte.
Alexandre Gomes
2
Es scheint, dass diese Methode einige Probleme hat, wenn der Schaltflächenstatus "hervorgehoben" ist. Das Bild kehrt in den Füllmodus zurück. Irgendeine Idee?
Yuanfei Zhu
Es funktioniert nicht für mich. Ich mache es jedoch mit [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stripImage] forState: UIControlStateNormal];
Mickey
3
Das hat bei mir funktioniert. Ich habe den Inhaltsmodus wie oben eingestellt. Sie müssen jedoch auch dasselbe Bild für den hervorgehobenen Status festlegen, um zu vermeiden, dass das Bild in den "Füllmodus" zurückkehrt. Beispiel: [imageButton setImage: image forState: UIControlStateHighlighted];
Christopher
1
Sie können dies in Interface Builder mit Schlüsselpfad imageView.contentMode, Typ Numberund Wert 1
tun
107

Keine der Antworten hier hat wirklich für mich funktioniert, ich habe das Problem mit dem folgenden Code gelöst:

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

Sie können dies auch im Interface Builder tun.

Geben Sie hier die Bildbeschreibung ein

nalexn
quelle
5
Dies gibt Ihnen kein Aspekt-Fit- Verhalten, wie vom OP gefordert.
Ortwin Gentz
3
@OrtwinGentz ​​können Sie den Modus auswählen und Aspect fitstattdessen einstellen scale to fill.
Daniel
55

Der einfachste Weg , um programmatisch einen UIButton Imageview in gesetzt Aspekte fit - Modus:

Schnell

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

Ziel c

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

Hinweis: Sie können .scaleAspectFit ändern (UIViewContentModeScaleAspectFit) zu .scaleAspectFill (UIViewContentModeScaleAspectFill) ein setzen Aspekt fill Modus

Tanguy G.
quelle
20

Ich hatte Probleme damit, dass die Größe des Bilds nicht proportional geändert wurde, sodass bei der Art und Weise, wie ich es reparierte, Kanteneinsätze verwendet wurden.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
Ninjaneer
quelle
16

Dies kann jetzt über die UIButton-Eigenschaften von IB erfolgen. Der Schlüssel ist, Ihr Bild als Hintergrund festzulegen, sonst funktioniert es nicht.

Geben Sie hier die Bildbeschreibung ein

Capikaw
quelle
14

Wenn Sie Daves Antwort erweitern, können Sie die Anzahl der contentModeSchaltflächen imageViewin IB ohne Code mithilfe der Laufzeitattribute festlegen:

Geben Sie hier die Bildbeschreibung ein

  • 1bedeutet UIViewContentModeScaleAspectFit,
  • 2würde bedeuten UIViewContentModeScaleAspectFill.
Ortwin Gentz
quelle
8

Wenn Sie einfach Ihr Schaltflächenbild verkleinern möchten:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
Tulleb
quelle
Das sollte yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit sein;
SDsykes
Ich habe es nicht mit .imageView versucht. Es funktioniert ohne ziemlich gut.
Tulleb
5

1 - Löschen Sie den Standardtext der Schaltfläche (wichtig).

2 - Ausrichtung wie Bild einstellen

3 - Stellen Sie den Inhaltsmodus wie das Bild ein

Geben Sie hier die Bildbeschreibung ein

Hamid Reza Ansari
quelle
Schöne Antwort, Bruder ... hat mir sehr geholfen. Vielen Dank!
BharathRao
5

Ich habe eine Methode, die das für mich erledigt. Die Methode nimmt UIButtonund passt den Bildaspekt an.

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

Die sauberste Lösung ist die Verwendung des automatischen Layouts . Ich habe die Priorität des Inhaltskomprimierungswiderstands von mir gesenkt UIButtonund das Bild (nicht das Hintergrundbild ) über den Interface Builder festgelegt . Danach habe ich ein paar Einschränkungen hinzugefügt, die die Größe meiner Schaltfläche definieren (in meinem Fall ziemlich komplex), und es hat wie ein Zauber funktioniert.

Rudolf Adamkovič
quelle
Dies hat bei mir funktioniert - aber nur, wenn ich das "Hintergrundbild" ausgewählt habe, nicht das eigentliche Bild. Was auch immer funktioniert! Das hat mich verrückt gemacht.
Andy
Unter Xcode 6.2 funktionierte dies für mich, aber wie @AndrewHeinlein sagte, verwendetBackground Image
RoLYroLLs
3

Stellen Sie sicher, dass Sie das Bild auf die Eigenschaft Image gesetzt haben, nicht jedoch auf den Hintergrund

Andrew
quelle
2

Das Hintergrundbild kann tatsächlich so eingestellt werden, dass die Aspektfüllung ziemlich einfach skaliert wird. Ich muss nur so etwas in einer Unterklasse von UIButton tun:

- (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
quelle
Ist das nicht ohne Unterklasse möglich?
Iulian Onofrei
Diese Antwort war speziell für backgroundImage. Für das Hauptbild können Sie mit den imageEdgeInsets Affen spielen.
Andy Poes
Ich weiß, und ich wollte, ob es möglich ist, dies ohne eine Unterklasse zu erreichen.
Iulian Onofrei
Soweit ich weiß, können Sie das backgroundImage nicht ohne Unterklasse anpassen.
Andy Poes
1

Swift 5.0

 myButton2.contentMode = .scaleAspectFit
 myButton2.contentHorizontalAlignment = .fill
 myButton2.contentVerticalAlignment = .fill
Qasim Mirza
quelle
0

Für Xamarin.iOS (C #):

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

Sie müssen nur den Inhaltsmodus der UIButton-Bildansicht für drei Ereignisse festlegen. - -

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

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

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

Wir haben Code für drei Ereignisse beim Hervorheben oder Auswählen, wenn die Schaltflächengröße QUADRATISCH und die Bildgröße rechteckig ist, wird zum Zeitpunkt des Hervorhebens oder Auswählens ein quadratisches Bild angezeigt.

Ich bin sicher, dass es für Sie funktionieren wird.

ruyamonis346
quelle
Sie stellen keinen Inhaltsmodus ein, sondern das Bild. Und sie sind keine Ereignisse, sie sind Staaten. Du machst ein großes Durcheinander. Dies hat nichts mit der Frage zu tun.
Manecosta