Atualizado para o Swift 5
preferredLayoutAttributesFittingAttributes
renomeado para preferredLayoutAttributesFitting
e usar o dimensionamento automático
Atualizado para o Swift 4
systemLayoutSizeFittingSize
renomeado para systemLayoutSizeFitting
Atualizado para iOS 9
Depois de ver minha solução GitHub quebrar no iOS 9, finalmente tive tempo de investigar o problema completamente. Atualizei agora o repositório para incluir vários exemplos de configurações diferentes para células com dimensionamento automático. Minha conclusão é que as células de auto-dimensionamento são ótimas em teoria, mas confusas na prática. Uma palavra de cautela ao prosseguir com células de auto-dimensionamento.
TL; DR
Confira meu projeto do GitHub
As células de auto-dimensionamento são suportadas apenas com o layout de fluxo, portanto, verifique se é isso que você está usando.
Há duas coisas que você precisa configurar para que as células com auto-dimensionamento funcionem.
1. Set estimatedItemSize
onUICollectionViewFlowLayout
O layout do fluxo se tornará dinâmico por natureza quando você definir a estimatedItemSize
propriedade.
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
2. Adicione suporte para dimensionamento na subclasse da sua célula
Isso vem em 2 sabores; Layout automático ou substituição personalizada de preferredLayoutAttributesFittingAttributes
.
Crie e configure células com o Layout automático
Não vou entrar em detalhes sobre isso, pois há uma brilhante publicação de SO sobre a configuração de restrições para uma célula. Apenas tenha cuidado com o fato de o Xcode 6 ter quebrado um monte de coisas com o iOS 7, portanto, se você suporta o iOS 7, precisará fazer coisas como garantir que a autoresizingMask seja definida no contentView da célula e que os limites do contentView sejam definidos como os limites da célula quando a célula está carregada (ou seja awakeFromNib
).
O que você precisa saber é que sua célula precisa ser mais seriamente restringida do que uma célula de exibição de tabela. Por exemplo, se você deseja que sua largura seja dinâmica, sua célula precisa de uma restrição de altura. Da mesma forma, se você deseja que a altura seja dinâmica, precisará de uma restrição de largura para sua célula.
Implemente preferredLayoutAttributesFittingAttributes
em sua célula personalizada
Quando essa função é chamada, sua visualização já foi configurada com conteúdo (ou seja cellForItem
, foi chamada). Supondo que suas restrições foram definidas adequadamente, você pode ter uma implementação como esta:
//forces the system to do one layout pass
var isHeightCalculated: Bool = false
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}
NOTA No iOS 9, o comportamento mudou um pouco, o que poderia causar falhas na sua implementação, se você não tomar cuidado (veja mais aqui ). Ao implementar, preferredLayoutAttributesFittingAttributes
você precisa garantir que você altere apenas o quadro dos atributos de layout uma vez. Se você não fizer isso, o layout chamará sua implementação indefinidamente e, eventualmente, falhará. Uma solução é armazenar em cache o tamanho calculado em sua célula e invalidá-lo sempre que você reutilizar a célula ou alterar seu conteúdo, como fiz com a isHeightCalculated
propriedade
Experimente seu layout
Nesse ponto, você deve ter células dinâmicas 'funcionando' em seu collectionView. Ainda não achei a solução pronta para uso suficiente durante meus testes, portanto, fique à vontade para comentar se você tiver. Ainda parece que UITableView
vence a batalha pelo dimensionamento dinâmico do IMHO.
Ressalvas
Lembre-se de que, se você estiver usando células protótipo para calcular o estimadoItemSize - isso será interrompido se o seu XIB usar classes de tamanho . A razão para isso é que, quando você carrega sua célula de um XIB, sua classe de tamanho será configurada Undefined
. Isso só será interrompido no iOS 8 ou superior, já que no iOS 7 a classe de tamanho será carregada com base no dispositivo (iPad = Regular-Qualquer, iPhone = Compact-Qualquer). Você pode definir o estimadoItemSize sem carregar o XIB ou carregar a célula do XIB, adicioná-la ao collectionView (isso definirá o traitCollection), executar o layout e removê-lo da superview. Como alternativa, você também pode fazer com que seu celular substitua o traitCollection
getter e retorne as características apropriadas. Você decide.
Deixe-me saber se eu perdi alguma coisa, espero ter ajudado e boa sorte na codificação