przeskalować obraz w UIButton do AspectFit?


97

Chcę dodać obraz do UIButton, a także chcę przeskalować mój obraz, aby pasował do UIButton (pomniejszyć obraz). Pokaż mi, proszę, jak to zrobić.

Oto, czego próbowałem, ale to nie działa:

  • Dodanie obrazu do przycisku i użycie setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Tworzenie „rozciągniętego obrazu”:
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];

Myślę, że zostało to zmienione na domyślne zachowanie w oprogramowaniu sprzętowym 4.0 i nowszych.
— Shaun Budhram

1
Rozwiązanie znajdziesz na stackoverflow.com/a/28205566/481207 .
— Matt

Odpowiedzi:


28

Jeśli naprawdę chcesz przeskalować obraz, zrób to, ale przed użyciem zmień jego rozmiar. Zmiana rozmiaru w czasie wykonywania spowoduje po prostu utratę cykli procesora.

Oto kategoria, której używam do skalowania obrazu:

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

Możesz go użyć do żądanego rozmiaru. Lubić :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];

Dzięki za odpowiedź, Gcamp. Miałem metodę zmiany rozmiaru według proporcji. Ale wciąż próbuję znaleźć sposób, by powiedzieć UIButtonowi, żeby zrobił to za mnie. Mój obraz jest ładowany z Internetu, więc nie mogę zmienić jego rozmiaru w czasie kompilacji. Przy okazji, bardzo dziękuję za twoją odpowiedź.
— KONG

2
Ponieważ obraz jest umieszczony w CALayer, renderowany i przechowywany w pamięci podręcznej przez Quartz, wydajność nie powinna być gorsza, jeśli umieścisz go tam w pełnym rozmiarze. Tak czy inaczej, zmieniasz rozmiar ~ 1 raz. Odpowiedź gcamp jest o wiele ważniejsza, jeśli ciągle zmieniasz rozmiar przycisku lub robisz inne rzeczy, które spowodowałyby ponowne narysowanie warstwy obrazu przez Quartz.
— Ben Gotow

wydaje się, że jakość obrazu jest obniżona. testuję na iPhonie 6 plus. Czy to prawda? Mam też zdjęcie 3x.
— Khant Thu Linn

Tak, ten kod jest dość stary. To było UIGraphicsBeginImageContextzamiast UIGraphicsBeginImageContextWithOptions. Właśnie to naprawiłem.
— gcamp

tak, ale w wielu przypadkach nie ma znaczenia, czy stracisz kilka cykli, więc nie ma sensu napełniać barana
— Radu Simionescu

204

Miałem ten sam problem. Wystarczy ustawić ContentMode ImageView, który znajduje się wewnątrz UIButton.

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

Mam nadzieję że to pomoże.


14
Upewnij się, że ustawiasz imageView . Przez chwilę nie zauważyłem też, że nadal korzystam z backgroundImageView i nie działa na to.
— Alexandre Gomes

2
Wygląda na to, że ta metoda ma pewne problemy, gdy stan przycisku jest „podświetlony”. Obraz powróci do trybu wypełnienia. Dowolny pomysł?
— Yuanfei Zhu

Na mnie to nie działa. Jednak sprawiam, że to działa, używając [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stretchImage] forState: UIControlStateNormal];
— Mickey,

3
To zadziałało dla mnie. Ustawiłem tryb treści jak wyżej. Należy jednak również ustawić ten sam obraz w stanie podświetlenia, aby uniknąć powrotu obrazu do „trybu wypełnienia”. Na przykład [imageButton setImage: image forState: UIControlStateHighlighted];
— Christopher

1
Możesz to zrobić w programie Interface Builder ze ścieżką klucza imageView.contentMode, typem Numberi wartością1
— bendytree

109

Żadna z odpowiedzi tutaj naprawdę nie zadziałała, rozwiązałem problem za pomocą następującego kodu:

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

Możesz to również zrobić w programie Interface Builder.

wprowadź opis obrazu tutaj


5
To nie zapewnia zachowania dopasowania aspektu, o które prosi OP.
— Ortwin Gentz

3
@OrtwinGentz ​​możesz wybrać tryb i ustawić Aspect fitzamiast scale to fill.
— Daniel

55

Najłatwiejszy sposób na programowe ustawienie UIButton imageView w trybie dopasowania proporcji :

Szybki

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

Cel C

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

Uwaga: możesz zmienić .scaleAspectFit (UIViewContentModeScaleAspectFit) na .scaleAspectFill (UIViewContentModeScaleAspectFill), aby ustawić tryb wypełniania proporcji


20

Miałem problemy z nieproporcjonalną zmianą rozmiaru obrazu, więc naprawiłem to za pomocą wstawek krawędziowych.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);

16

Można to teraz zrobić za pomocą właściwości UIButton IB. Kluczem jest ustawienie obrazu jako tła, w przeciwnym razie to nie zadziała.

wprowadź opis obrazu tutaj


14

Rozwijając odpowiedź Dave'a, możesz ustawić wszystkie contentModeprzyciski imageVieww IB, bez żadnego kodu, używając atrybutów środowiska wykonawczego:

wprowadź opis obrazu tutaj

  • 1znaczy UIViewContentModeScaleAspectFit,
  • 2znaczyłoby UIViewContentModeScaleAspectFill.

8

Jeśli chcesz po prostu zmniejszyć obraz przycisku:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);

Powinno to być yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
— sdsykes

Nie próbowałem z .imageView. Działa bez całkiem dobrze.
— Tulleb

6

1 - wyczyść domyślny tekst przycisku (ważne)

2 - ustaw wyrównanie jak obraz

3 - ustaw tryb treści, taki jak obraz

wprowadź opis obrazu tutaj


Dobra odpowiedź, stary… bardzo mi pomogła. Dzięki!
— BharathRao

5

Mam metodę, która robi to za mnie. Metoda przyjmuje UIButtoni dopasowuje proporcje obrazu.

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

4

Najczystszym rozwiązaniem jest użycie Auto Layout . Spuściłem Content Compression Resistance Priorytet z moich UIButtoni ustawić obraz (nie Tło obrazu ) za pośrednictwem interfejsu Builder . Potem dodałem kilka ograniczeń, które definiują rozmiar mojego przycisku (dość skomplikowanego w moim przypadku) i działało to jak urok.


U mnie to zadziałało - ale tylko wtedy, gdy wybrałem opcję „Obraz tła”, a nie rzeczywisty obraz. Cokolwiek działa! To doprowadzało mnie do NUTS.
— Andy

W Xcode 6.2 działało to dla mnie, ale jak powiedział @AndrewHeinlein, używaneBackground Image
— RoLYroLLs

3

upewnij się, że ustawiłeś obraz na właściwość Image, ale nie na Background


2

Obraz tła można w rzeczywistości ustawić tak, aby dość łatwo skalował wypełnienie według aspektu. Wystarczy zrobić coś takiego w podklasie 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;
}

Czy nie jest to możliwe bez podklasy?
— Iulian Onofrei

Ta odpowiedź dotyczyła w szczególności backgroundImage. W przypadku głównego obrazu można małpować za pomocą elementu imageEdgeInsets.
— Andy Poes

Wiem i chciałem, żeby można to osiągnąć bez podklasy.
— Iulian Onofrei

O ile wiem, nie można dostosować backgroundImage bez podklasy.
— Andy Poes

1

Swift 5.0

 myButton2.contentMode = .scaleAspectFit
 myButton2.contentHorizontalAlignment = .fill
 myButton2.contentVerticalAlignment = .fill

0

W przypadku platformy Xamarin.iOS (C #):

    myButton.VerticalAlignment = UIControlContentVerticalAlignment.Fill;
    myButton.HorizontalAlignment = UIControlContentHorizontalAlignment.Fill;
    myButton.ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;

-1

Wystarczy ustawić tryb treści widoku obrazu UIButton dla trzech zdarzeń. -

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

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

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

Mamy kod dla trzech zdarzeń bcoz podczas podświetlania lub wybierania, jeśli rozmiar przycisku to KWADRAT, a rozmiar obrazu to prostokąt, to pokaże kwadratowy obraz w momencie podświetlania lub wybierania.

Jestem pewien, że to zadziała.


Nie ustawiasz trybu treści, tylko ustawiasz obraz. I to nie są wydarzenia, to stany. Robisz duży bałagan. To jest zupełnie niezwiązane z pytaniem.
— manecosta
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.