O problema de correção automática do quadro UICollectionViewCell do contentView na célula do protótipo do Storyboard (Xcode 6, iOS 8 SDK) acontece quando é executado apenas no iOS 7

Estou usando o Xcode 6 Beta 3, iOS 8 SDK. Construa o Target iOS 7.0 usando o Swift. Por favor, consulte o meu problema passo a passo com screenshots abaixo.

Eu tenho um UICollectionView no Storyboard. 1 Protótipo UICollectionViewCell que contém 1 label no centro (sem regra de auto-redimensionamento). O fundo roxo era para marcar um contentView que é gerado em tempo de execução pelo Cell, eu acho. Essa visão será redimensionada corretamente com base no meu UICollectionViewLayoutDelegate eventualmente, mas não no iOS 7. Observe que estou usando o Xcode 6 e o ​​problema só acontece no iOS 7.

Quando eu construo o aplicativo no iOS 8. Tudo está bem.

Nota: Roxo é o contentView , azul é meu UIButton com canto arredondado.

http://i.stack.imgur.com/uDNDY.png

No entanto, no iOS 7, todos os subViews dentro do Cell encolhem repentinamente para o frame de (0,0,50,50) e nunca mais se ajustam à minha regra de Autoresizing.

http://i.stack.imgur.com/lOZH9.png

Eu suponho que este é um bug no iOS 8 SDK ou Swift ou talvez Xcode?


Atualização 1: Esse problema ainda existe no Xcode 6.0.1 oficial! O melhor trabalho é semelhante ao que KoCMoHaBTa sugeriu abaixo, definindo o quadro em cellForItem da célula (você tem que subclass sua célula embora). Descobriu-se que isso é uma incompatibilidade entre o iOS 8 SDK e o iOS 7 (confira a resposta da ecotax citada abaixo na Apple).

Atualização 2: cole este código no início do seu cellForItem e as coisas devem estar bem:

/** Xcode 6 on iOS 7 hot fix **/ cell.contentView.frame = cell.bounds; cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; /** End of Xcode 6 on iOS 7 hot fix **/ 

contentView está corrompido. Também pode ser corrigido em awakeFromNib

ObjC:

 -(void)awakeFromNib { [super awakeFromNib]; self.contentView.frame = self.bounds; self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; } 

Swift3:

 override func awakeFromNib() { super.awakeFromNib() self.contentView.frame = self.bounds self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] } 

Eu encontrei o mesmo problema e pedi ajuda à Apple DTS. Sua resposta foi:

No iOS 7, as visualizações de conteúdo das células são dimensionadas por meio de máscaras de redimensionamento automático. No iOS 8, isso foi alterado, as células pararam de usar as máscaras de redimensionamento e começaram a dimensionar a visualização de conteúdo no layoutSubviews. Se uma ponta for codificada no iOS 8 e decodificada no iOS 7, você terá uma visualização de conteúdo sem uma máscara de redimensionamento automático e nenhum outro meio pelo qual dimensionar a si mesmo. Então, se você alterar o quadro da célula, a visualização de conteúdo não será seguida.

Os aplicativos que estão sendo implantados de volta ao iOS 7 terão que resolver isso dimensionando a própria visualização de conteúdo, adicionando máscaras de redimensionamento automático ou adicionando restrições.

Eu acho que isso significa que não é um bug no XCode 6, mas uma incompatibilidade entre o iOS 8 SDK e o iOS 7 SDK, que o atingirá se você atualizar para o Xcode 6, porque ele começará automaticamente a usar o iOS 8 SDK.

Como comentei antes, a solução que Daniel Plamann descreveu funciona para mim. Os descritos por Igor Palaguta e KoCMoHaBTa parecem mais simples, e parecem fazer sentido dar resposta da Apple DTS, então vou tentar mais tarde.

Eu encontrei o mesmo problema e espero que a Apple corrija isso com a próxima versão do Xcode. Enquanto isso eu uso uma solução alternativa. Na minha subclass UICollectionViewCell acabei de replace o layoutSubviews e resize o contentView manualmente, caso o tamanho seja diferente do tamanho de collectionViewCell .

 - (void)layoutSubviews { [super layoutSubviews]; BOOL contentViewIsAutoresized = CGSizeEqualToSize(self.frame.size, self.contentView.frame.size); if( !contentViewIsAutoresized) { CGRect contentViewFrame = self.contentView.frame; contentViewFrame.size = self.frame.size; self.contentView.frame = contentViewFrame; } } 

Outra solução é definir o tamanho do contentView e as máscaras de atualização automática em -collectionView: cellForItemAtIndexPath: da seguinte maneira:

 -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellID = @"CellID"; UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; //set contentView frame and autoresizingMask cell.contentView.frame = cell.bounds; cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin; //You custom code goes here return cell; } 

Isso funciona também com o Layout automático, pois as máscaras de redimensionamento automático são convertidas em restrições.

No Xcode 6.0.1, o contentView for UICollectionViewCell é interrompido para dispositivos iOS7. Ele também pode ser corrigido adicionando restrições adequadas ao UICollectionViewCell e seu contentView nos methods awakeFromNib ou init.

  UIView *cellContentView = self.contentView; cellContentView.translatesAutoresizingMaskIntoConstraints = NO; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[cellContentView]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(cellContentView)]]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[cellContentView]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(cellContentView)]]; 

Isso não funcionará corretamente sem as outras soluções mencionadas devido a um bug no Xcode 6 GM com a forma como o Xcode compila arquivos xib no formato de nib. Embora eu não possa dizer com 100% de certeza que é relacionado ao Xcode e não tem a ver com o tempo de execução, estou muito confiante – eis como eu posso mostrá-lo:

  1. Build + Execute o aplicativo no Xcode 5.1.
  2. Vá para o diretório do aplicativo simulador e copie o arquivo .nib compilado para o xib com o qual você está tendo problemas.
  3. Build + Execute o aplicativo no Xcode 6 GM.
  4. Pare o aplicativo.
  5. Substitua o arquivo .nib na pasta do simulador do aplicativo recém-criado com o arquivo .nib criado usando o Xcode 5.1
  6. Reinicie o aplicativo do simulador, NÃO do Xcode.
  7. Seu celular carregado daquele .nib deve funcionar como esperado.

Espero que todos que lerem esta pergunta arquivem um Radar com a Apple. Este é um problema enorme e precisa ser resolvido antes da versão final do Xcode.

Edit: À luz do post ecotax , eu só queria atualizar isso para dizer que agora é confirmada as diferenças de comportamento entre a construção no iOS 8 vs iOS 7, mas não um bug. Meu hack corrigiu o problema, pois a criação do iOS 7 acrescentou a máscara de redimensionamento automático à visualização de conteúdo necessária para fazer esse trabalho, que a Apple não adiciona mais.

As respostas neste post funcionam, o que eu nunca entendi é porque funciona.

Primeiro, existem duas “regras”:

  1. Para visualizações criadas programaticamente (Ex. [UIView new] ), a propriedade translatesAutoresizingMaskIntoConstraints é definida como YES
  2. As visualizações criadas no construtor de interface, com o AutoLayout ativado, terão a propriedade translatesAutoresizingMaskIntoConstraints definida como NO

A segunda regra não parece se aplicar a visualizações de nível superior para as quais você não define restrições. (Ex. A visão de conteúdo)

Ao olhar para uma célula do Storyboard, observe que a célula não tem seu contentView exposto. Nós não estamos “controlando” o contentView , a Apple é.

Aprofunde-se no código-fonte do storyboard e veja como a célula do contentView está definida:

Agora subviews da célula (observe o translatesAutoresizingMaskIntoConstraints="NO" ):

O contentView não tem suas translatesAutoresizingMaskIntoConstraints definidas como NO . Além disso, falta definição de layout, talvez por causa do que @ecotax disse .

Se olharmos para o contentView , ele tem uma máscara de auto-redisposição, mas nenhuma definição para isso:

Portanto, há duas conclusões:

  1. contentView translatesAutoresizingMaskIntoConstraints está definido como YES .
  2. contentView carece de definição de layout.

Isso nos leva a duas soluções que foram discutidas.

Você pode definir as máscaras de awakeFromNib manualmente em awakeFromNib :

 self.contentView.frame = cell.bounds; self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 

Ou você pode definir o contentView para translatesAutoresizingMaskIntoConstraints awakeFromNib e definir restrições em - (void)updateConstraints .

Esta é a versão Swift da resposta de @ Igor que é aceita e obrigada pelo seu bom companheiro de respostas.

Primeiro, UICollectionViewCell sua subclass UICollectionViewCell e cole o código a seguir como ele está dentro da class.

 override func awakeFromNib() { super.awakeFromNib() self.contentView.frame = self.bounds self.contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth] } 

A propósito, estou usando o Xcode 7.3.1 e o Swift 2.3. Solução é testada no iOS 9.3, que está funcionando perfeitamente.

Obrigado, Espero que isso tenha ajudado.

Em swift, coloque o seguinte código na subclass da célula da visualização de coleção:

 override var bounds : CGRect { didSet { // Fix autolayout constraints broken in Xcode 6 GM + iOS 7.1 self.contentView.frame = bounds } } 

Descobri que também há problemas com o dimensionamento do contentView no iOS 8. Ele tende a ser exposto muito tarde no ciclo, o que pode causar conflitos temporários de restrição. Para resolver isso, adicionei o seguinte método em uma categoria de UICollectionViewCell :

 - (void)fixupContentView { #if __IPHONE_OS_VERSION_MAX_ALLOWED < 80100 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) { self.contentView.frame = self.bounds; self.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin; } else { [self layoutIfNeeded]; } #endif #endif } 

Esse método deve ser chamado após o desenfileiramento da célula.

Eu consertei fazendo isso:

 override func layoutSubviews() { contentView.superview?.frame = bounds super.layoutSubviews() } 

veja: aqui

Apenas certifique-se de marcar a checkbox de seleção “Autoresize subviews” na ponta da célula da view de coleção. Ele funcionará bem tanto no iOS 8 quanto no iOS 7.