UICollectionView animar itens após reloadItemsAtIndexPaths ser chamado (animação de fade).
Existe uma maneira de evitar essa animação?
iOS 6
Respostas:
É importante observar que, se você está direcionando o iOS 7 e superior, pode usar o novo UIView
método performWithoutAnimation:
. Suspeito que, por baixo do capô, isso está fazendo quase o mesmo que as outras respostas aqui (desativando temporariamente as UIView
animações / ações do Core Animation), mas a sintaxe é boa e limpa.
Então, para esta questão em particular ...
Objective-C:
[UIView performWithoutAnimation:^{
[self.collectionView reloadItemsAtIndexPaths:indexPaths];
}];
Rápido:
UIView.performWithoutAnimation {
self.collectionView.reloadItemsAtIndexPaths(indexPaths)
}
É claro que esse princípio pode ser aplicado a qualquer situação em que você deseja garantir que uma mudança não seja animada.
Você também pode tentar isto:
UICollectionView *collectionView;
...
[UIView setAnimationsEnabled:NO];
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
[UIView setAnimationsEnabled:YES];
}];
Também descobri que, se você envolver performBatchUpdates
em um bloco de animação UIView, a animação UIView será usada em vez da animação padrão, então você pode apenas definir a duração da animação para 0, assim:
[UIView animateWithDuration:0 animations:^{
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:nil];
}];
Isso é muito legal se você quiser usar animações elásticas do iOS 7 durante inserções e exclusões!
performBatchUpdates
dentro animateWithDuration
é brilhante! Obrigado pela dica!
UICollectionView animar itens após reloadItemsAtIndexPaths ser chamado (animação de fade).
Existe uma maneira de evitar essa animação?
iOS 6
Presumo que você esteja usando um FlowLayout. Já que você está tentando se livrar da animação de esmaecimento, tente isto:
import UIKit
class NoFadeFlowLayout: UICollectionViewFlowLayout {
override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = super.initialLayoutAttributesForAppearingItem(at: itemIndexPath)
attrs?.alpha = 1.0
return attrs
}
override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath)
attrs?.alpha = 1.0
return attrs
}
}
Essa é uma pergunta muito antiga, então provavelmente você não está mais voltado para o iOS 6. Eu estava trabalhando pessoalmente no tvOS 11 e tinha a mesma dúvida, então este está aqui para quem vem com o mesmo problema.
Eu escrevi uma categoria em UICollectionView para fazer exatamente isso. O truque é desativar todas as animações durante o recarregamento:
if (!animated) {
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
}
[self reloadItemsAtIndexPaths:indexPaths];
if (!animated) {
[CATransaction commit];
}
CATransaction.setDisableActions(true)
uma abreviação para isso.
extension UICollectionView {
func reloadWithoutAnimation(){
CATransaction.begin()
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
self.reloadData()
CATransaction.commit()
}
}
Aqui está uma versão do Swift 3 performBatchUpdates
sem animação para a UICollectionView
. Descobri que isso funcionou melhor para mim do que collectionView.reloadData()
porque reduziu a troca de células quando os registros foram inseridos.
func appendCollectionView(numberOfItems count: Int){
// calculate indexes for the items to be added
let firstIndex = dataItems.count - count
let lastIndex = dataItems.count - 1
var indexPaths = [IndexPath]()
for index in firstIndex...lastIndex {
let indexPath = IndexPath(item: index, section: 0)
indexPaths.append(indexPath)
}
UIView.performWithoutAnimation {
self.collectionView.performBatchUpdates({ () -> Void in
self.collectionView.insertItems(at: indexPaths)
}, completion: { (finished) -> Void in
})
}
}
- (void)reloadCollectionViewAnimated:(BOOL)animated {
if (animated) {
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
}];
} else {
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
[CATransaction commit];
}
}
Apenas para adicionar meus $ 0,02, tentei as duas versões da resposta selecionada, e a forma original funcionou melhor para meus objetivos. Estou trabalhando em uma visualização de calendário com rolagem infinita que permite ao usuário entrar no calendário em uma determinada semana e, em seguida, deslizar para frente e para trás e selecionar dias individuais para filtrar uma lista.
Na minha implementação, para manter o desempenho das coisas em dispositivos mais antigos, o conjunto de datas que representam a visualização do calendário deve ser mantido relativamente pequeno, o que significa manter cerca de 5 semanas de datas, com o usuário no meio na 3ª semana. O problema de usar a segunda abordagem é que há uma segunda etapa em que você precisa rolar a exibição da coleção de volta para o meio sem uma animação, o que torna uma aparência muito irregular por algum motivo com a animação de base bloqueada.
Meu código:
[UIView setAnimationsEnabled:NO];
[self.collectionView performBatchUpdates:^{
[self.collectionView deleteItemsAtIndexPaths:indexPathDeleteArray];
[self.collectionView insertItemsAtIndexPaths:indexPathAddArray];
} completion:NULL];
[UIView setAnimationsEnabled:YES];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:14 inSection:0];
[self.collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
func reloadRowsWithoutAnimation(at indexPaths: [IndexPath]) {
let contentOffset = collectionView.contentOffset
UIView.setAnimationsEnabled(false)
collectionView.performBatchUpdates {
collectionView.reloadItems(at: indexPaths)
}
UIView.setAnimationsEnabled(true)
collectionView.setContentOffset(contentOffset, animated: false)
}