OK, a resposta é não, não há como fazer isso sem subclassificar UICollectionViewFlowLayout.
No entanto, a criação de subclasses é incrivelmente fácil para qualquer um que esteja lendo isso no futuro.
Primeiro, configurei a chamada da subclasse MyCollectionViewFlowLayout
e, em seguida, no construtor de interface, alterei o layout de visualização da coleção para Customizado e selecionei minha subclasse de layout de fluxo.
Porque você está fazendo isso desta forma, você não pode especificar tamanhos de itens, etc ... em IB, então em MyCollectionViewFlowLayout.m eu tenho isso ...
- (void)awakeFromNib
{
self.itemSize = CGSizeMake(75.0, 75.0);
self.minimumInteritemSpacing = 10.0;
self.minimumLineSpacing = 10.0;
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.sectionInset = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
}
Isso configura todos os tamanhos para mim e a direção da rolagem.
Então ...
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
CGFloat offsetAdjustment = MAXFLOAT;
CGFloat horizontalOffset = proposedContentOffset.x + 5;
CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
CGFloat itemOffset = layoutAttributes.frame.origin.x;
if (ABS(itemOffset - horizontalOffset) < ABS(offsetAdjustment)) {
offsetAdjustment = itemOffset - horizontalOffset;
}
}
return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
Isso garante que a rolagem termine com uma margem de 5,0 na borda esquerda.
Isso é tudo que eu precisava fazer. Não precisei definir o layout do fluxo no código.
targetContentOffsetForProposedContentOffset:withVelocity
não está sendo chamado por mim quando eu rolar. O que está acontecendo?A solução de Dan é falha. Ele não lida bem com o movimento do usuário. Os casos em que o usuário movimenta rapidamente e a rolagem não se move tanto, apresentam falhas de animação.
Minha implementação alternativa proposta tem a mesma paginação proposta antes, mas lida com a movimentação do usuário entre as páginas.
fonte
Versão rápida da resposta aceita.
Válido para Swift 5 .
fonte
Esta é minha implementação no Swift 5 para paginação baseada em células verticais :
Algumas notas:
itemSize
realmente corresponde ao tamanho do item, pois isso costuma ser um problema, especialmente ao usarcollectionView(_:layout:sizeForItemAt:)
, use uma variável personalizada com o itemSize.self.collectionView.decelerationRate = UIScrollView.DecelerationRate.fast
.Aqui está uma versão horizontal (não testei completamente, então, perdoe quaisquer erros):
Este código é baseado no código que uso em meu projeto pessoal, você pode conferir aqui baixando-o e executando o destino Exemplo.
fonte
Embora essa resposta tenha sido uma grande ajuda para mim, há uma oscilação perceptível quando você desliza rapidamente em uma pequena distância. É muito mais fácil reproduzi-lo no dispositivo.
Descobri que isso sempre acontece quando
collectionView.contentOffset.x - proposedContentOffset.x
evelocity.x
tem cantos diferentes.Minha solução foi garantir que
proposedContentOffset
seja maior do quecontentOffset.x
se a velocidade fosse positiva e menos se fosse negativa. Está em C #, mas deve ser bastante simples de traduzir para Objective C:Este código está usando
MinContentOffset
,MaxContentOffset
eSnapStep
que deve ser trivial para você definir. No meu caso, eles acabaram sendofonte
Depois de longos testes, encontrei uma solução para ajustar ao centro com largura de célula personalizada (cada célula tem largura de diferença) que corrige a cintilação. Sinta-se à vontade para melhorar o roteiro.
fonte
consulte esta resposta de Dan Abramov aqui está a versão Swift
ou gist aqui https://gist.github.com/katopz/8b04c783387f0c345cd9
fonte
Para quem procura uma solução que ...
collectionView.contentInset
(e a safeArea no iPhone X) em consideraçãoentão por favor veja abaixo ...
fonte
Aqui está minha solução Swift em uma exibição de coleção de rolagem horizontal. É simples, doce e evita qualquer cintilação.
fonte
itemSize
??pageWidth()
deve usarminimumLineSpacing
uma vez que rola horizontalmente. E, no meu caso, tenho umacontentInset
visualização para a coleção de modo que a primeira e a última célula possam ser centralizadas, então eu usolet xOffset = pageWidth() * index - collectionView.contentInset.left
.um pequeno problema que encontrei ao usar targetContentOffsetForProposedContentOffset é um problema com a última célula não ajustando de acordo com o novo ponto que retornei.
Descobri que o CGPoint que retornei tinha um valor Y maior do que o permitido, então usei o seguinte código no final da minha implementação targetContentOffsetForProposedContentOffset:
só para deixar mais claro, esta é a minha implementação de layout completo, que apenas imita o comportamento de paginação vertical:
espero que isso poupe algum tempo e uma dor de cabeça para alguém
fonte
Eu prefiro permitir que o usuário folheie várias páginas. Então aqui está minha versão
targetContentOffsetForProposedContentOffset
(baseada na resposta da DarthMike) para layout vertical .fonte
A resposta de Fogmeister funcionou para mim, a menos que eu rolei até o final da linha. Minhas células não se encaixam perfeitamente na tela, de modo que rolaria até o final e voltaria com um movimento brusco, de modo que a última célula sempre se sobrepusesse à borda direita da tela.
Para evitar isso, adicione a seguinte linha de código no início do método targetcontentoffset
fonte
Código @ André Abreu
Versão Swift3
fonte
Swift 4
A solução mais fácil para visualização de coleção com células de um tamanho (rolagem horizontal):
fonte
Uma solução mais curta (supondo que você esteja armazenando em cache os atributos de layout):
Para colocar isso em contexto:
fonte
Para ter certeza de que funciona na versão Swift (swift 5 agora), usei a resposta do @ André Abreu, acrescento mais algumas informações:
Ao subclassificar UICollectionViewFlowLayout, o "override func awakeFromNib () {}" não funciona (não sei por quê). Em vez disso, usei "override init () {super.init ()}"
Este é meu código colocado na classe SubclassFlowLayout: UICollectionViewFlowLayout {}:
Após a subclasse, certifique-se de colocar isso em ViewDidLoad ():
fonte
Para quem procura uma solução em Swift:
fonte
Aqui está uma demonstração para paginação por célula (quando rolar rápido, não pular uma ou mais células): https://github.com/ApesTalk/ATPagingByCell
fonte