web-dev-qa-db-fra.com

Défilement automatique UICollectionView vers une cellule à IndexPath

Avant de charger la vue de collection, l'utilisateur définit le nombre d'images dans le tableau de la vue de collection. Toutes les cellules ne tiennent pas sur l'écran. J'ai 30 cellules et seulement 6 à l'écran.

La question: comment faire défiler automatiquement la cellule avec l'image souhaitée au chargement d'UICollectionView?

90
AlexanderZ

J'ai constaté que le défilement dans viewWillAppear peut ne pas fonctionner correctement car la vue de collection n'a pas encore fini sa mise en page; vous pouvez faire défiler le mauvais article.

J'ai également constaté que le défilement dans viewDidAppear ferait apparaître un flash momentané de la vue non défilée.

De plus, si vous faites défiler chaque fois viewDidLayoutSubviews, l'utilisateur ne pourra pas faire défiler manuellement car certaines dispositions de collection entraînent une présentation de sous-vue à chaque fois que vous faites défiler.

Voici ce que j'ai trouvé fonctionne de manière fiable:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    // If we haven't done the initial scroll, do it once.
    if (!self.initialScrollDone) {
        self.initialScrollDone = YES;

        [self.collectionView scrollToItemAtIndexPath:self.myInitialIndexPath
                                    atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
    }
}
76
LenK

Nouvelle réponse modifiée:

Ajoutez ceci dans viewDidLayoutSubviews

rapide

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let indexPath = IndexPath(item: 12, section: 0)
    self.collectionView.scrollToItem(at: indexPath, at: [.centeredVertically, .centeredHorizontally], animated: true)
}

Normalement, .centerVertically est le cas

ObjC

-(void)viewDidLayoutSubviews {
   [super viewDidLayoutSubviews];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
   [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically | UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}

Ancienne réponse fonctionnant pour iOS plus ancien

Ajoutez ceci dans viewWillAppear:

[self.view layoutIfNeeded];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
160
boweidmann

Je suis totalement d'accord avec la réponse ci-dessus. La seule chose est que pour moi la solution a été définie le code dans viewDidAppear

viewDidAppear 
{
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
}

Lorsque j'ai utilisé le viewWillAppear, le défilement n'a pas fonctionné.

13
raistlin

Swift:

your_CollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)

Swift

let indexPath = IndexPath(row: itemIndex, section: sectionIndex)

collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.right, animated: true)

Position de défilement:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically
11
Rajesh Loganathan

cela a semblé fonctionner pour moi, sa semblable à une autre réponse mais a quelques différences distinctes:

- (void)viewDidLayoutSubviews
{     
   [self.collectionView layoutIfNeeded];
   NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
   NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
   NSIndexPath *nextItem = [NSIndexPath indexPathForItem:someInt inSection:currentItem.section];

   [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
11
greenhouse

Vous pouvez utiliser GCD pour répartir le défilement dans la prochaine itération de la boucle d'exécution principale dans viewDidLoad afin d'obtenir ce problème. Le défilement sera effectué avant que la vue de collection ne soit affichée à l'écran. Il n'y aura donc pas de clignotement.

- (void)viewDidLoad {
    dispatch_async (dispatch_get_main_queue (), ^{
        NSIndexPath *indexPath = YOUR_DESIRED_INDEXPATH;
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    });
}
8
Tianyu Wang

Je recommanderais de le faire dans collectionView: willDisplay: Ensuite, vous pouvez être sûr que le délégué de la vue de collection livre quelque chose. Voici mon exemple:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    /// this is done to set the index on start to 1 to have at index 0 the last image to have a infinity loop
    if !didScrollToSecondIndex {
        self.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: false)
        didScrollToSecondIndex = true
    }
}
4
Eike

Toutes les réponses ici - hacks. J'ai trouvé un meilleur moyen de faire défiler la vue de la collection quelque part après relaodData:
Disposition de la vue de collection de la sous-classe, quelle que soit la disposition que vous utilisiez, substituez la méthode prepareLayout, après le super appel, définissez le décalage dont vous avez besoin.
ex: https://stackoverflow.com/a/34192787/1400119

1
trickster77777