dimensionar a imagem em um UIButton para AspectFit?

94

Eu quero adicionar uma imagem a um UIButton, e também quero escalar minha imagem para caber com o UIButton (tornar a imagem menor). Por favor, me mostre como fazer.

Tentei fazer isso, mas não deu certo:

  • Adicionando imagem ao botão e usando setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Fazendo uma "imagem esticada":
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];
KONG
fonte
Acho que isso foi alterado para ser o comportamento padrão no firmware 4.0 e superior.
Shaun Budhram
1
Consulte stackoverflow.com/a/28205566/481207 para obter a solução.
Matt

Respostas:

28

Se você realmente deseja dimensionar uma imagem, faça-o, mas deve redimensioná-la antes de usá-la. Redimensionar em tempo de execução apenas perderá ciclos de CPU.

Esta é a categoria que estou usando para dimensionar uma imagem:

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

Você pode usá-lo no tamanho que desejar. Gostar :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];
gcamp
fonte
Obrigado pela sua resposta, Gcamp. Eu tinha um método para redimensionar por proporção. Mas eu ainda tento encontrar uma maneira de dizer ao UIButton que faça isso por mim. Minha imagem é carregada da Internet, então não posso redimensioná-la em tempo de compilação. BTW, muito obrigado pela sua resposta.
KONG
2
Como a imagem é colocada em um CALayer, renderizada e armazenada em cache pelo Quartz, o desempenho não deve ser pior se você colocá-la em tamanho real. De qualquer forma, você está redimensionando cerca de 1 vez. A resposta do gcamp é muito mais importante se você estiver constantemente redimensionando o botão ou fazendo outras coisas que acionariam o Quartz para redesenhar a camada da imagem.
Ben Gotow
parece que a qualidade da imagem é reduzida. Estou testando no iphone 6 plus. É verdade? Eu também tenho imagem 3x.
Khant Thu Linn
Sim, este código é muito antigo. Foi em UIGraphicsBeginImageContextvez de UIGraphicsBeginImageContextWithOptions. Apenas consertei.
gcamp
sim, mas em muitos casos não importa se você perder alguns ciclos, então não adianta encher o carneiro
Radu Simionescu
203

Eu tive o mesmo problema. Basta definir o ContentMode do ImageView que está dentro do UIButton.

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

Espero que isto ajude.

Dave
fonte
14
Certifique-se de definir o imageView . Também não percebi, por um momento, que ainda estava usando backgroundImageView e não estava funcionando para isso.
Alexandre Gomes
2
Parece que este método tem alguns problemas quando o estado do botão está 'destacado'. A imagem voltará ao modo de preenchimento. Qualquer ideia?
Yuanfei Zhu
Não está funcionando para mim. No entanto, faço isso funcionar usando [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stretchImage] forState: UIControlStateNormal];
Mickey
3
Isso funcionou para mim. Eu defino o modo de conteúdo como acima. No entanto, você também precisa definir a mesma imagem do estado destacado para evitar que a imagem volte ao "modo de preenchimento". Por exemplo, [imageButton setImage: image forState: UIControlStateHighlighted];
Christopher
1
Você pode fazer isso no Interface Builder com caminho imageView.contentMode, tipo Numbere valor da chave1
bendytree
107

Nenhuma das respostas aqui realmente funcionou para mim. Resolvi o problema com o seguinte código:

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

Você também pode fazer isso no Interface Builder.

insira a descrição da imagem aqui

nalexn
fonte
5
Isso não dá a você um comportamento de ajuste de aspecto conforme solicitado pelo OP.
Ortwin Gentz
3
@OrtwinGentz ​​você pode selecionar o modo e definir em Aspect fitvez de scale to fill.
Daniel
55

A maneira mais fácil de definir programaticamente um UIButton imageView no modo de ajuste de aspecto :

Rápido

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

Objective-C

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

Nota: Você pode alterar .scaleAspectFit (UIViewContentModeScaleAspectFit) para .scaleAspectFill (UIViewContentModeScaleAspectFill) para definir um preenchimento de aspecto modo de

Tanguy G.
fonte
20

Tive problemas com a imagem não redimensionada proporcionalmente, então a maneira que eu consertei foi usando inserções de borda.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
ninjaneer
fonte
16

Isso agora pode ser feito por meio das propriedades UIButton do IB. A chave é definir sua imagem como plano de fundo, caso contrário, não funcionará.

insira a descrição da imagem aqui

Capikaw
fonte
14

Expandindo a resposta de Dave, você pode definir o contentModedos botões imageViewtodos em IB, sem nenhum código, usando os atributos de tempo de execução:

insira a descrição da imagem aqui

  • 1significa UIViewContentModeScaleAspectFit,
  • 2significaria UIViewContentModeScaleAspectFill.
Ortwin Gentz
fonte
8

Se você simplesmente deseja reduzir a imagem do botão:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
Tulleb
fonte
Deve ser yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
sdsykes
Não tentei com .imageView. Está funcionando muito bem sem.
Tulleb
5

1 - limpar o texto padrão do botão (importante)

2 - definir alinhamento como imagem

3 - definir modo de conteúdo como imagem

insira a descrição da imagem aqui

Hamid Reza Ansari
fonte
Boa resposta mano ... me ajudou muito. Obrigado!
BharathRao
5

Eu tenho um método que faz isso por mim. O método pega UIButtone ajusta o aspecto da imagem.

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

A solução mais limpa é usar o Auto Layout . Baixei conteúdo Prioridade resistência à compressão do meu UIButtone definir a imagem (não Imagem de fundo ) via Interface Builder . Depois disso, adicionei algumas restrições que definem o tamanho do meu botão (bastante complexo no meu caso) e funcionou perfeitamente.

Rudolf Adamkovič
fonte
Isso funcionou para mim - mas apenas se eu selecionasse usar a "Imagem de fundo", não a imagem real. Tudo o que funciona! Isso estava me deixando louca.
Andy
No Xcode 6.2 isso funcionou para mim, mas como @AndrewHeinlein disse, usadoBackground Image
RoLYroLLs de
3

certifique-se de ter definido a imagem para a propriedade Image, mas não para a propriedade Background

Andrew
fonte
2

A imagem de fundo pode ser configurada para dimensionar o preenchimento do aspecto com bastante facilidade. Só precisa fazer algo assim em uma subclasse 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
fonte
Isso não é possível sem uma subclasse?
Iulian Onofrei 01 de
Esta resposta foi especificamente para backgroundImage. Para a imagem principal, você pode usar o imageEdgeInsets.
Andy Poes
Eu sei, e queria se isso fosse possível sem uma subclasse.
Iulian Onofrei 01 de
Até onde eu sei, você não pode ajustar backgroundImage sem criar subclasses.
Andy Poes
1

Swift 5.0

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

Para Xamarin.iOS (C #):

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

Você só precisa definir o modo de conteúdo do UIButton imageview para três eventos. -

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

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

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

Temos código para três eventos bcoz enquanto destacamos ou selecionamos se o tamanho do botão é QUADRADO e o tamanho da imagem é retângulo, então ele mostrará a imagem quadrada no momento do destaque ou seleção.

Tenho certeza de que funcionará para você.

ruyamonis346
fonte
Você não está definindo um modo de conteúdo, você está definindo a imagem. E não são eventos, são estados. Você está fazendo uma grande bagunça. Isso não tem nenhuma relação com a questão.
manecosta