J'ai essayé de définir la durée (avec les méthodes habituelles) pour définir la durée de l'animation pour la méthode selectItemAtIndexPath:animated:scrollPosition:
de UICollectionView (ou la méthode scrollToItemAtIndexPath:atScrollPosition:animated:
). J'ai essayé [UIView setAnimationDuration]
et j'ai essayé de l'envelopper dans une CATransaction
. Jusqu'à présent, je n'ai pas réussi à changer cette durée d'animation (bien que j'avoue que j'aurais pu me tromper dans cette logique).
Pensées?
METTRE À JOUR:
J'ai essayé un bon nombre d'approches ici. La solution la plus proche est de faire ce que nous ferions normalement pour l’animation UIScrollView
(en définissant l’argument animated: sur NO
et en l’enveloppant dans un bloc d’animation UIView
). Cela fonctionne parfaitement pour le scrollview. Cependant, cela s’affine avec le processus de création UICollectionView
pour une raison quelconque.
J'ai inclus un exemple ci-dessous en utilisant deux approches. Chaque approche suppose que vous avez 4 sections avec 4 éléments dans chaque section. En outre, l’animation suppose que vous passez de 0,0 à 3,3.
Utilisation de l'animation par défaut
Une partie du problème ici semble certainement liée à UICollectionView
. Si vous utilisez l'approche suivante (en utilisant l'option d'animation par défaut), tout fonctionne correctement:
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
Lors de son exécution, chaque cellule située entre les cellules visibles actuelles et la cellule de destination est créée. J'ai inclus la journalisation sur la méthode collectionView:cellForItemAtIndexPath:
:
2013-05-18 09:33:24.366 DEF-CV-Testing[75463:c07] Transition
Cell Created for Index Path: <NSIndexPath 0x8913f40> 2 indexes [0, 1]
Cell Created for Index Path: <NSIndexPath 0x75112e0> 2 indexes [0, 2]
Cell Created for Index Path: <NSIndexPath 0xfe1a6c0> 2 indexes [0, 3]
Cell Created for Index Path: <NSIndexPath 0x89159e0> 2 indexes [1, 0]
Cell Created for Index Path: <NSIndexPath 0x8a10e70> 2 indexes [1, 1]
Cell Created for Index Path: <NSIndexPath 0x7510d90> 2 indexes [1, 2]
Cell Created for Index Path: <NSIndexPath 0x75112a0> 2 indexes [1, 3]
Cell Created for Index Path: <NSIndexPath 0x8915a00> 2 indexes [2, 0]
Cell Created for Index Path: <NSIndexPath 0x75111c0> 2 indexes [2, 1]
Cell Created for Index Path: <NSIndexPath 0xfe17f30> 2 indexes [2, 2]
Cell Created for Index Path: <NSIndexPath 0xfe190c0> 2 indexes [2, 3]
Cell Created for Index Path: <NSIndexPath 0xfe16920> 2 indexes [3, 0]
Cell Created for Index Path: <NSIndexPath 0x75112a0> 2 indexes [3, 1]
Cell Created for Index Path: <NSIndexPath 0xfe1a4f0> 2 indexes [3, 2]
Cell Created for Index Path: <NSIndexPath 0x75142d0> 2 indexes [3, 3]
Utilisation d'une animation personnalisée
Lors de la compression de la méthode scrollToItemAtIndexPath:
dans un bloc d'animation UIView
, les éléments ne sont pas créés correctement. Voir exemple de code ici:
[UIView animateWithDuration:5.0 delay:0.0 options:0 animations:^{
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:NO];
} completion:^(BOOL finished) {
NSLog(@"Completed");
}];
Les cellules actuellement visibles disparaissent et seule celle de destination est créée. J'ai inclus la même journalisation sur la méthode collectionView:cellForItemAtIndexPath:
:
Transition
Cell Created for Index Path: <NSIndexPath 0x71702f0> 2 indexes [3, 3]
Completed
J'ai eu des problèmes similaires avec UITableView
que j'ai résolus avec le code suivant:
[CATransaction begin];
[CATransaction setCompletionBlock:onCompletion];
[CATransaction setAnimationDuration:duration];
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
[CATransaction commit];
De toute évidence, vous ne pouvez pas l'appeler avec animated:NO
car le code d'animation dans la méthode est important. Utiliser une CATransaction
pour envelopper l'animation a fonctionné pour moi.
Pour moi, cela fonctionne. De toute évidence, il a besoin de quelques ajustements (pour obtenir une heure plus précise et pour faire défiler en arrière, de bas en haut. À présent, il ne prend en charge que le défilement vertical de haut en bas).
Appelez quelque chose comme ça:
[self scrollToIndexPath:[NSIndexPath indexPathForItem:40 inSection:0] withAnimationDuration:3.0f];
et voici le code
-(void)scrollToIndexPath:(NSIndexPath *)path withAnimationDuration:(float)duration
{
NSIndexPath *firstCell = [[self.collectionView indexPathsForVisibleItems] objectAtIndex:0];
UICollectionViewLayoutAttributes *attributesForFirstCell = [self.collectionView layoutAttributesForItemAtIndexPath:firstCell];
CGRect firstCellRect = attributesForFirstCell.frame;
CGPoint startPoint = firstCellRect.Origin;
NSIndexPath *destinationCell = path;
UICollectionViewLayoutAttributes *attributesForDestCell = [self.collectionView layoutAttributesForItemAtIndexPath:destinationCell];
CGRect destCellRect = attributesForDestCell.frame;
CGPoint destPoint = destCellRect.Origin;
self.destination = destPoint;
float delta = destPoint.y - startPoint.y;
float cycle = (delta / (50*duration));
self.pass = (int)cycle + 1;
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(scrollView) userInfo:nil repeats:YES];
}
- (void) scrollView {
float w = self.pass;
CGPoint scrollPoint = self.collectionView.contentOffset;
scrollPoint.y = scrollPoint.y + w;
if (scrollPoint.y >= self.destination.y)
[self.myTimer invalidate];
[self.collectionView setContentOffset: scrollPoint animated: NO];
}
Que faire si vous mettez du code dans scrollViewDidScroll:
?
J'ai un problème similaire que j'ai résolu en appelant selectItemAtIndexPath:animated:scrollPosition
, puis en utilisant scrollViewDidScroll:
pour exécuter ce que je voudrais habituellement exécuter dans un bloc d'achèvement.
Bien sûr, vous devrez probablement garder trace de BOOL
ou deux pour décider si vous devez exécuter quoi que ce soit dans scrollViewDidScroll:
.
Je peux le faire fonctionner en l’enveloppant dans UIView.animate avec animated false :
UIView.animate(withDuration: 0.7, delay: 0.0, options: .curveEaseInOut, animations: {
self.collectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .centeredHorizontally, animated: false)
}, completion: nil)
Vous pouvez le faire proprement avec la bibliothèque AnimationEngine . Il enveloppe une variable CADisplayLink
dans une syntaxe d'animation basée sur des blocs. J'ai posté une réponse ici avec un exemple de code qui anime contentOffset
. Il vous suffit de faire la conversion de indexPath en contentOffset.