Estou tentando obter o dimensionamento UICollectionViewCells
automático trabalhando com o Layout automático, mas não consigo fazer com que as células se dimensionem de acordo com o conteúdo. Estou tendo problemas para entender como o tamanho da célula é atualizado a partir do conteúdo do conteúdo da célula.
Aqui está a configuração que eu tentei:
- Personalizado
UICollectionViewCell
com umUITextView
no seu contentView. - A rolagem para
UITextView
está desativada. - A restrição horizontal do contentView é: "H: | [_textView (320)]", ou seja,
UITextView
é fixada à esquerda da célula com uma largura explícita de 320. - A restrição vertical do contentView é: "V: | -0 - [_ textView]", ou seja,
UITextView
fixada na parte superior da célula. - A
UITextView
restrição de altura é definida como uma constante na qual osUITextView
relatórios cabem no texto.
Aqui está o que parece com o fundo da célula definido como vermelho e o UITextView
fundo definido como azul:
Coloquei o projeto com o qual estou jogando no GitHub aqui .
Respostas:
Atualizado para o Swift 5
preferredLayoutAttributesFittingAttributes
renomeado parapreferredLayoutAttributesFitting
e usar o dimensionamento automáticoAtualizado para o Swift 4
systemLayoutSizeFittingSize
renomeado parasystemLayoutSizeFitting
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.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 personalizadaQuando 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: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 aisHeightCalculated
propriedadeExperimente 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 otraitCollection
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
fonte
estimatedItemSize
leva a falhas - parece haver algum bug enorme na maneira como o layout automático está tentando processar o UICollectionViewCell.No iOS10, há uma nova constante chamada
UICollectionViewFlowLayout.automaticSize
(anteriormenteUICollectionViewFlowLayoutAutomaticSize
); portanto, em vez disso:você pode usar isso:
Ele tem melhor desempenho, especialmente quando as células na exibição de coleção têm wid constante
Acessando o layout de fluxo:
Swift 5 Atualizado:
fonte
collectionViewLayout
e apenas verificar se é do tipoUICollectionViewFlowLayout
Algumas mudanças importantes na resposta de Daniel Galasko todos os meus problemas. Infelizmente, ainda não tenho reputação suficiente para comentar diretamente.
Na etapa 1, ao usar o Layout automático, basta adicionar um UIView pai único à célula. TUDO dentro da célula deve ser uma subvisão do pai. Isso respondeu a todos os meus problemas. Enquanto o Xcode adiciona isso para o UITableViewCells automaticamente, não o faz (mas deveria) para o UICollectionViewCells. De acordo com os documentos :
Em seguida, pule completamente a etapa 3. Não é necessário.
fonte
contentView
, o Xcode reclama que está em conflito com a propriedade existente. Tentei adicionar subvisõesself.contentView
e definir restrições para isso e o aplicativo trava.No iOS 10+, esse é um processo muito simples de duas etapas.
Certifique-se de que todo o conteúdo da sua célula seja colocado em um único UIView (ou dentro de um descendente do UIView, como o UIStackView, que simplifica muito o layout automático). Assim como no redimensionamento dinâmico de UITableViewCells, toda a hierarquia de visualizações precisa ter restrições configuradas, do contêiner mais externo à mais interna. Isso inclui restrições entre o UICollectionViewCell e o childview imediato
Instrua o layout do fluxo do seu UICollectionView a dimensionar automaticamente
fonte
UICollectionViewFlowLayout.automaticSize
foi renomeado paraUICollectionViewFlowLayoutAutomaticSize
.Adicione flowLayout em viewDidLoad ()
Além disso, defina um UIView como mainContainer para sua célula e adicione todas as visualizações necessárias dentro dela.
Consulte este incrível e impressionante tutorial para obter mais referências: UICollectionView com célula de dimensionamento automático usando o autolayout no iOS 9 e 10
fonte
EDIT 19/19/19: para o iOS 13, basta usar UICollectionViewCompositionalLayout com alturas estimadas. Não perca seu tempo lidando com essa API quebrada.
Depois de lutar com isso por algum tempo, notei que o redimensionamento não funciona para o UITextViews se você não desativar a rolagem:
fonte
mistério da âncora contentView:
Em um caso bizarro, isso
não funcionaria. Adicionadas quatro âncoras explícitas ao contentView e ele funcionou.
e como sempre
no
YourLayout: UICollectionViewFlowLayout
Quem sabe? Pode ajudar alguém.
Crédito
https://www.vadimbulavin.com/collection-view-cells-self-sizing/
tropeçou na ponta lá - nunca a vi em nenhum outro lugar em todos os artigos da 1000s sobre isso.
fonte
Eu fiz uma altura de célula dinâmica da exibição de coleção. Aqui está o repositório git hub .
E descubra por que o preferidoLayoutAttributesFittingAttributes é chamado mais de uma vez. Na verdade, ele será chamado pelo menos 3 vezes.
A imagem do log do console:
1º preferidoLayoutAttributesFittingAttributes :
O layoutAttributes.frame.size.height é o status atual 57.5 .
2º preferidoLayoutAttributesFittingAttributes :
A altura do quadro da célula foi alterada para 534,5 conforme o esperado. Mas, a exibição de coleção ainda tem altura zero.
Terceiro preferidoLayoutAttributesFittingAttributes :
Você pode ver que a altura da visualização da coleção foi alterada de 0 para 477 .
O comportamento é semelhante ao manipular rolagem:
No começo, pensei que esse método chamasse apenas uma vez. Então, eu codifiquei da seguinte maneira:
Está linha:
causará loop infinito na chamada do sistema e falha no aplicativo.
Qualquer tamanho alterado, ele validará oLayoutAttributesFittingAttributes preferido de todas as células repetidamente até que as posições de todas as células (ou seja, quadros) não sejam mais alteradas.
fonte
Além das respostas acima,
Apenas certifique-se de definir propriedade estimadoItemSize de UICollectionViewFlowLayout para algum tamanho e não implemente sizeForItem: atIndexPath método delegado.
É isso aí.
fonte
Se você implementar o método UICollectionViewDelegateFlowLayout:
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath
Quando você liga
collectionview performBatchUpdates:completion:
, a altura do tamanho será usada emsizeForItemAtIndexPath
vez depreferredLayoutAttributesFittingAttributes
.O processo de renderização
performBatchUpdates:completion
passará pelo método,preferredLayoutAttributesFittingAttributes
mas ignorará suas alterações.fonte
Para quem puder ajudar,
Eu tive aquele acidente desagradável se
estimatedItemSize
foi definido. Mesmo se eu retornasse 0 polnumberOfItemsInSection
. Portanto, as próprias células e seu layout automático não foram a causa da falha ... O collectionView apenas travou, mesmo quando vazio, apenas porqueestimatedItemSize
foi configurado para o dimensionamento automático.No meu caso, reorganizei meu projeto, de um controlador contendo um collectionView para um collectionViewController, e funcionou.
Vai saber.
fonte
collectionView.collectionViewLayout.invalidateLayout()
depoiscollectionView.reloadData()
.Para quem tentou de tudo sem sorte, essa é a única coisa que faz com que funcione para mim. Para os rótulos de várias linhas dentro da célula, tente adicionar esta linha mágica:
Mais informações: aqui
Felicidades!
fonte
O método de exemplo acima não compila. Aqui está uma versão corrigida (mas não testada para saber se funciona ou não).
fonte
Atualize mais informações:
Se você usar
flowLayout.estimatedItemSize
, sugira usar a versão posterior do iOS8.3. Antes do iOS8.3, ele falha[super layoutAttributesForElementsInRect:rect];
. A mensagem de erro é*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Segundo, na versão iOS8.x,
flowLayout.estimatedItemSize
fará com que configurações diferentes de inserção de seção não funcionem. ou seja, a função:(UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:
.fonte
A solução compreende 4 etapas importantes:
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
contentView
-o nas bordas da célula, poiscontentView
impede o dimensionamento automático, pois ele não tem o layout automático ativado.collectionView(:cellForItemAt:)
para limitar a largura do contentView à largura do collectionView.Isso acontece da seguinte maneira; vamos definir célula
maxWidth
variável para largura de CollectionView emcollectionView(:cellForItemAt:)
e emmaxWidth
'sdidSet
método que vai definir widthAnchor.constant para maxWidth.Como você deseja ativar o dimensionamento automático do UITextView, ele possui uma etapa adicional para;
4. Calcule e defina o heightAnchor.constant do UITextView.
Assim, sempre que a largura da contentView está definido vamos ajustar a altura de UITextView ao longo de
didSet
demaxWidth
.Por dentro do UICollectionViewCell:
Essas etapas obterão o resultado desejado. Aqui está uma essência executável completa
Agradecemos a Vadim Bulavin por sua postagem clara e esclarecedora no blog - Tamanho da exibição das células: tutorial passo a passo
fonte
Tentei usar,
estimatedItemSize
mas havia muitos bugs ao inserir e excluir células, se aestimatedItemSize
altura não fosse exatamente igual à da célula. parei de definirestimatedItemSize
e implementei células dinâmicas usando uma célula protótipo. aqui está como isso é feito:crie este protocolo:
implemente este protocolo em seu costume
UICollectionViewCell
:Agora faça com que o seu controlador esteja em conformidade com
UICollectionViewDelegateFlowLayout
, e nele, tenha este campo:será usado como uma célula de protótipo para vincular dados e, em seguida, determinar como esses dados afetaram a dimensão que você deseja que seja dinâmica
finalmente, o
UICollectionViewDelegateFlowLayout's
collectionView(:layout:sizeForItemAt:)
deve ser implementado:e é isso. Retornar o tamanho da célula
collectionView(:layout:sizeForItemAt:)
dessa maneira, impedindo-me de usarestimatedItemSize
e inserir e excluir células funciona perfeitamente.fonte