UIButton não escuta a configuração do modo de conteúdo?

91

firstButton é um UIButton do tipo Custom. Estou colocando programaticamente três deles em cada célula de uma tabela, assim:

[firstButton setImage:markImage forState:UIControlStateNormal];
[firstButton setContentMode:UIViewContentModeScaleAspectFit];
[cell.contentView addSubview:firstButton];

Em outro lugar, estou dizendo ao clipToBounds. O que obtenho é um recorte do quadrado central da imagem, ao invés de uma renderização em escala de aspecto dele. Eu tentei fazer isso de várias maneiras, incluindo definir a propriedade mode em firstButton.imageView, que também não parece funcionar.

Dan Ray
fonte
1
Veja a solução de Chris Nolet abaixo: button.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
Matt,
Consulte stackoverflow.com/a/28205566/481207 que mostra que a configuração de contentVerticalAlignment e contentHorizontalAlignment é necessária para UIViewContentModeScaleAspectFit.
Matt

Respostas:

186

Eu tive o mesmo problema. Vejo que esta pergunta é um pouco antiga, mas quero fornecer uma resposta clara e correta para poupar outras pessoas (como eu) algum tempo quando ela aparecer nos resultados da pesquisa.

Levei um pouco de pesquisa e experimentação, mas encontrei a solução. Basta definir o ContentMode do ImageView "oculto" que está dentro do UIButton.

[[firstButton imageView] setContentMode: UIViewContentModeScaleAspectFit];
[firstButton setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];

Talvez seja a isso que Dan Ray estava aludindo em sua resposta aceita, mas suspeito que não.

Dave
fonte
1
Não, não foi. A solução que decidi foi usar um UIImageView para manter a imagem e, em seguida, um UIButton claro e transparente do tipo "personalizado" em cima dela.
Dan Ray
Dave, pelo menos no iOS 3.2, sua solução parece não funcionar para mim. Que pena, pois esperava conseguir o destaque da imagem no clique "de graça". Eu até me certifiquei de que button.imageView não era nulo onde eu estava definindo contentMode, e defini a imagem após definir contentMode, assim como você está fazendo.
Jacques
2
Só para esclarecer, "não funciona" significa "a imagem é mostrada em sua resolução total, não reduzida como eu esperava".
Jacques
Jacques, o descrito acima funciona para mim no iOS 4.x. Infelizmente, posso reproduzir o problema "não redimensiona" ao compilar com um destino v3.2. Tentei alterar o tamanho do quadro da visualização UIButton, mas isso também não pareceu ajudar. ugh.
Dave,
4
Veja a solução de Chris Nolet abaixo: button.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
Matt,
74

Se você estiver lidando com a imagem do UIButton (ao contrário de seu backgroundImage), definir o contentMode no próprio UIButton ou em seu imageView não tem efeito (apesar do que outras respostas dizem).

Alternativamente, faça o seguinte:

self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
self.button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;

Ou dimensione sua imagem de acordo.

OU apenas use um UIImageView (que respeite adequadamente o contentMode) com um UITapGestureRecognizer anexado a ele ou um UIButton transparente em cima dele.

Alfie Hanssen
fonte
4
Isso funciona para o meu caso no iOS 7, enquanto todos os outros aqui não.
Byte de
5
Definir contentHorizontalAlignment e contentVerticalAlignment é a solução correta. Consulte stackoverflow.com/a/28205566/481207 para obter uma explicação.
Matt
1
Essa é a resposta que eu estava procurando.
ninjaneer
4
Esta resposta está incorreta. Você não precisa definir contentModeno imageViewse você quiser fazer qualquer tipo de preenchimento aspecto ou ajuste, como outras respostas esclareceram. Consulte: stackoverflow.com/a/7944316/746890 .
Chris Nolet
50

Em vez de definir a contentModeno próprio botão, você vai querer definir contentHorizontalAlignmente contentVerticalAlignmentpropriedades e (crucialmente) o contentModepara o botão de imageViewpara qualquer tipo de preenchimento aspecto ou forma. Aqui está um exemplo:

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

Claro, você também pode fazer outras coisas como alinhar a imagem do botão à parte superior do botão. Se você não precisa de um preenchimento de aspecto ou ajuste, pode apenas definir o alinhamento:

button.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;

No Swift, você vai querer usar:

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

Isso funciona para todas as versões do iOS, incluindo as versões mais recentes com layout automático (ou seja, iOS 4 até iOS 11+).

Chris Nolet
fonte
2
Obrigado, Chris - isso resolveu meu problema, ou melhor, resolveu em combinação com contentEdgeInsets, a fim de afastar um pouco minha imagem da borda superior.
Rob Reuss
7

Depois de algumas horas de confusão, veja como fiz para funcionar no iOS 3.2. Como dusker mencionou, usar setBackgroundImage em vez de setImage fez o trabalho para mim.

CGRect myButtonFrame = CGRectMake(0, 0, 250, 250);
UIImage *myButtonImage = [UIImage imageNamed:@"buttonImage"];

UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];

[myButton setBackgroundImage:myButtonImage forState:UIControlStateNormal];
[myButton setFrame: myButtonFrame];
[myButton setContentMode: UIViewContentModeScaleAspectFit];
Pierre
fonte
6

A resposta é usar um UIImageView com todas as lindas configurações de Content Mode que você deseja e, em seguida, colocar um botão personalizado em cima dele. Idiota que você não pode fazer tudo de uma vez, mas parece que não pode.

Dan Ray
fonte
4

Encontrou uma solução para isso. Defina a adjustsImageWhenHighlightedpropriedade de UIButtoncomo NO.

  UIButton *b = [[UIButton alloc] initWithFrame:rect];
        [b setImage:image forState:UIControlStateNormal];
        [b.imageView setContentMode:UIViewContentModeScaleAspectFill];
        [b setAdjustsImageWhenHighlighted:NO];

Espero que isto ajude. Sinta-se à vontade para comentar abaixo, responderei em quaisquer dúvidas que você tenha.

iOSDevSF
fonte
Esta é a solução perfeita.
Gaurav
Não funciona. Isso apenas evita que o botão seja destacado.
Matt
4

Minha resposta é semelhante à de Kuba. Eu precisava que minha imagem fosse configurada de maneira programática.

UIImage *image = [[UIImage alloc] initWithContentsOfFile:...];
[button setBackgroundImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFill; //this is needed for some reason, won't work without it.
for(UIView *view in button.subviews) {
    view.contentMode = UIViewContentModeScaleAspectFill;
}
ninjaneer
fonte
3

Única solução que funcionou para mim:

[button setImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFill;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
Tariq
fonte
3

Swift 3

self.firstButton.imageView?.contentMode = .scaleAspectFill
Vaibhav Saran
fonte
1

Em vez de setImage, tente setBackgroundImage

mais escuro
fonte
3
Hmp. A, isso é idiota, deveria respeitar a configuração do MODO DE CONTEÚDO para o seu CONTEÚDO, certo? E B, ele AINDA não parece respeitar a configuração do modo - agora está bloqueado para "esticar" (que é, neste caso, mais como "espremer") e não está dimensionando o conteúdo em relação ao seu aspecto Razão.
Dan Ray
1

Acredito que temos um problema simples com o construtor de interface aqui - aparentemente, o IB ignora qualquer alteração no modo de conteúdo DEPOIS de você definir a propriedade da imagem.

a solução é tão simples: definir o modo de conteúdo, remover nomes de imagem previamente definidos (certifique-se de removê-lo em todos os estados, padrão, destacado, etc.) e, em seguida, inserir novamente os nomes de imagem desejados em todos os estados desejados - et voilà .

JohnPayne
fonte
1
o mesmo acontece com o modo de conteúdo definido de forma programática - não defina a imagem ANTES de definir o modo de conteúdo
JohnPayne
0

Também aconselho dar uma olhada na adjustsImageWhenHighlighted UIButtonpropriedade para evitar estranhas deformações da imagem, quando o botão é pressionado.

MonsieurDart
fonte
0

Ao tentar descobrir isso, meu método ficou um pouco mais hackeado com o passar do tempo, e acabei criando uma subclasse de UIButton e substituindo setHighlighted:

Para mim, funciona apenas para reduzir o alfa da imagem para 0,5, porque eles estão em um fundo preto.

No entanto, só funciona se eu comentar [super setHighlighted:] (onde parece que o código esticado de imagem está acontecendo), o que simplesmente não parece a maneira certa de resolver isso ... tudo parece ser funcionando bem, no entanto. Veremos como funciona à medida que continuo trabalhando nisso.

- (void)setHighlighted:(BOOL)highlight {
    if (highlight) {
        [self.imageView setAlpha:.5];
    }  else {
        [self.imageView setAlpha:1];        
    }

//    [super setHighlighted:highlight];
}
Jankins
fonte
1
No caso de alguém achar isso relevante, meu método acima parecia funcionar bem até que eu coloquei os botões em um UIScrollView, onde às vezes o destaque do botão "travava", o que eu suspeitava que poderia eventualmente acontecer.
jankins,
0

Se alguém procura uma resposta que funcione no iOS 6 e iOS 7 e storyboard:

Você pode definir a imagem em seu storyboard:

insira a descrição da imagem aqui

E depois:

for(UIView* testId in self.subviews) {
    if([testId isKindOfClass:[UIImageView class]])
        [testId setContentMode:UIViewContentModeScaleAspectFill];
}
Jakub
fonte
0

Se o UIButton parece não escutar as configurações de restrição de layout, verifique se as imagens são maiores que o tamanho do botão. Sempre use as imagens @ 2x e @ 3x para resoluções de retina.

Totoro
fonte
0

Essas duas coisas (que são bastante difíceis de encontrar inicialmente) irão esticar sua imagem UIButton para caber no tamanho do botão:

insira a descrição da imagem aqui insira a descrição da imagem aqui

deve-se sempre tentar definir isso no Storyboard em vez de no código.

delta2flat
fonte