UIButton não vai para Aspect Fit no iPhone

105

Eu tenho alguns UIButtons e no IB eles estão configurados para Aspect Fit, mas por alguma razão eles estão sempre se alongando. Existe algo mais que você precisa definir? Tentei todos os modos de visualização diferentes e nenhum deles funcionou, todos eles se estendem.

marty
fonte
A resposta de @Werner Altesischer é a correta. Faça as alterações apropriadas.
Harshit Gupta
1
@marty Você está definindo uma imagem de fundo ou imagem? imagem de fundo não suporta, apenas imagem.
Juan Boero

Respostas:

45

Eu já tive esse problema antes. Eu resolvi isso colocando minha imagem em um UIImageView, onde as contentModeconfigurações realmente funcionam, e colocando um personalizado transparente UIButtonem cima disso.

EDIT: Esta resposta é obsoleta. Veja a resposta de @Werner Altewischer para a resposta correta nas versões modernas do iOS.

Dan Ray
fonte
Sim, tentei isso, mas agora não consigo obter o botão para reajustar à imagem
marty
Como você gerencia estados de botão com esta técnica? Parece que responder à interação do usuário como "destacado" seria um pesadelo.
SooDesuNe
3
Esta pode ter sido a maneira certa de fazer isso há 2,5 anos, quando esta pergunta foi respondida, mas agora você pode editar o ImageView interno do UIButton e definir o modo de conteúdo lá. Veja a resposta de @Werner Altewischer
Steve Haley,
233

A solução é definir o contentModena imageViewpropriedade do UIButton. O UIButtondeve ser criado com um tipo personalizado para que funcione, eu acredito (caso contrário, nilé retornado para esta propriedade).

Werner Altewischer
fonte
67
Isso funcionou para mim:[button.imageView setContentMode:UIViewContentModeScaleAspectFit];
ayreguitar
2
Isso funciona para mim também, mas se eu definir adjustsImageWhenHighlighted = YES, a imagem é esticada novamente quando eu toco no botão.
cduck
1
O alongamento em ajusta imagem foi eliminado no iOS 6.
Ben Flynn
3
No iOS 8, isso realmente não funciona para mim. A resposta original (com colocar um imageView atrás de um botão transparente) funciona melhor.
user1416564
3
em Swift du jour:button.imageView!.contentMode = UIViewContentMode.scaleAspectFit
Nestor
57

Este método funcionou muito bem para mim .:

No Xib selecione o botão e definauser defined runtime attributes :

  • Caminho da chave: self.imageView.contentMode
  • Tipo: Number
  • Valor: 1

Clique aqui para ver mais claramente a solução

Usamos número porque você não pode usar enum aqui. Mas o UIViewContentModeScaleAspectFit é igual a 1.

István Stefánovics
fonte
2
Isso também atualizou a imagem no construtor de interface durante o tempo de design. Ótima solução.
George Filippakos
Ótima solução, pouco código e funciona perfeitamente, o enum é baseado em itens da lista do modo de conteúdo.
Kross
Você também pode adicionar uma extensão para facilitar um pouco: extension UIButton { @IBInspectable var imageContentMode: Int { get {return imageView?.contentMode.rawValue ?? 0} set {imageView?.contentMode = UIViewContentMode(rawValue: newValue) ?? .scaleAspectFit} } }
Yonat
Sem 'self' imageView.contentModefuncionou para mim!
porJeevan
22

Se estiver fazendo isso no Interface Builder, você pode usar o inspetor de atributos do Runtime para definir isso diretamente, sem qualquer código.

Defina o caminho da chave no botão como "imageView.contentMode" com um tipo de "Número" e um valor de "1" (ou qualquer modo que você desejar).

imageview.contentMode = 1

averydev
fonte
14

Use imageView do botão para contentMode. Não diretamente no próprio botão.

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

Se você colocar a imagem UIImageViewatrás do botão, perderá a funcionalidade embutida da UIButtonclasse, como adjustsImageWhenHighlightede e adjustsImageWhenDisabled, claro, a capacidade de definir imagens diferentes para estados diferentes (sem o embaraço de fazer isso sozinho).

Se quisermos ter uma imagem não expandida para todos os estados de controle , uma abordagem é obter a imagem usando imageWithCGImage:scale:orientation, como no seguinte método:

- (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;
}

Para implementar isso, escreveríamos:

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

Isso deve evitar que a imagem se estique em todos os estados de controle. Funcionou para mim, mas deixe-me saber se não funcionar!

NOTA: Aqui estamos tratando de um problema relacionado a UIButton, mas insideButton:pode muito bem ser insideView:, ou qualquer outra coisa em que se gostaria de ajustar a imagem.

Alexander Wallin
fonte
6

Eu tive esse problema um tempo atrás. O problema que tive é que estava tentando aplicar esse efeito ao UIButton de fundo, o que é limitado e, portanto, significa que você não pode ajustá-lo tão facilmente.

O truque é configurá-lo apenas como uma imagem e então aplicar a técnica de @ayreguitar e isso deve consertar!

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

Isso funcionou para mim

[button.imageView setContentMode:UIViewContentModeScaleAspectFit];

Obrigado a @ayreguitar pelo seu comentário

Karan Alangat
fonte
4

Aqui está uma resposta alternativa rápida:

myButton.imageView?.contentMode = .ScaleAspectFit
João neves
fonte
4

Combinando algumas respostas diferentes em uma solução - crie um botão com um tipo personalizado, defina a propriedade imageView contentMode do botão e defina a imagem para o botão (não a imagem de fundo, que ainda será dimensionada para preencher).

//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)
Vigarista
fonte
3
btn.imageView.contentMode = UIViewContentModeScaleAspectFit;
Selaband
fonte
Embora este snippet de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade de sua postagem. Lembre-se de que você está respondendo à pergunta para leitores no futuro e essas pessoas podem não saber os motivos de sua sugestão de código. - Da revisão
Ferrybig
2

Esta resposta é baseada na resposta de @WernerAltewischer .

Para evitar conectar meu botão a um IBOutlet para executar o código nele, criei uma subclasse da classe UIButton:

// .h
@interface UIButtonWithImageAspectFit : UIButton
@end

// .m
@implementation UIButtonWithImageAspectFit

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

@end



Agora crie um botão personalizado em seu xib e defina sua imagem (não a imagem de fundo):

UIButtonWithImageAspectFit: criar e definir imagem


Em seguida, defina sua classe:

UIButtonWithImageAspectFit: definir classe personalizada

Você Terminou!
Ao invés de
UIButton sem ajuste de aspecto de imagem
aspecto da imagem do botão, o ajuste agora é o esperado:
UIButton com ajuste de aspecto de imagem

Guillaume
fonte
2

ios 12. Você precisa adicionar também o Alinhamento de conteúdo

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
fonte
1

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
1

Os modos de conteúdo UIView se aplicam ao "conteúdo" do CALayer correspondente. Isso funciona para UIImageViews porque eles definem o CALayerconteúdo como o correspondente CGImage.

drawRect: no final, renderiza para o conteúdo da camada.

Um custom UIButton(até onde eu sei) não tem conteúdo (os botões de estilo de retângulo arredondado podem ser renderizados usando conteúdo). O botão tem subvisualizações: o plano de fundo UIImageView, a imagem UIImageViewe o título UILabel. Definir o contentModenas subvisualizações pode fazer o que você quiser, mas mexer com a UIButtonhierarquia de visões é um pouco inconveniente.

tc.
fonte
1

Mudar UIButton.imageView.contentModenão funcionou para mim.
Resolvi o problema configurando a imagem para a propriedade 'Background'.
Você pode adicionar restrição de proporção se precisar

Parque Soohwan
fonte
1

Isso se sobrepõe a muitas das outras respostas, mas a solução para mim foi

  • defina o contentModedo UIImageViewpara o botão para .ScaleAspectFit- o que pode ser feito em "Atributos de tempo de execução definidos pelo usuário" no Construtor de interface (ou seja self.imageView.contentMode, número, 1) ou em umUIButton subclasse;
  • desabilite ”Autoresize Subviews”;
  • defina ”Borda” como ”Imagem” e os valores apropriados ”Superior” e ”Inferior” para ”Inserção” (que só podem ser necessários se você, como eu, usou um PDF como imagem).
Plindberg
fonte
0

Você pode usar imageWithCGImage conforme mostrado acima (mas sem os parênteses ausentes).

Além disso ... milhões de telefones diferentes do 4.0 não funcionarão com esse código.

Alice
fonte
0

[button sizeToFit] trabalhou para mim.

Hila
fonte
0

Semelhante a @Guillaume, criei uma subclasse de UIButton como um arquivo Swift. Em seguida, defina minha classe personalizada no Interface Builder:

construtor de interface.

E aqui está o arquivo Swift:

import UIKit

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

Eu tive o mesmo problema, mas não consegui fazer funcionar (talvez seja um bug com o SDK).

Eventualmente, como uma solução alternativa, coloquei um UIImageViewatrás do meu botão e defini as opções que eu queria UIButtonnele , então simplesmente coloquei um espaço em branco em cima dele.

Anshu Chimala
fonte
7
Existe um eco aqui? ;-)
Dan Ray