UICollectionView scrollt automatisch zu Zelle bei IndexPath


101

Vor dem Laden der Sammlungsansicht legt der Benutzer die Anzahl der Bilder im Array der Sammlungsansicht fest. Alle Zellen passen nicht auf den Bildschirm. Ich habe 30 Zellen und nur 6 auf dem Bildschirm.

Die Frage: Wie kann beim Laden von UICollectionView automatisch zur Zelle mit dem gewünschten Bild gescrollt werden?

Antworten:


90

Ich habe das Scrollen gefunden viewWillAppear möglicherweise nicht zuverlässig funktioniert, da das Layout der Sammlungsansicht noch nicht fertig ist. Sie können zum falschen Element scrollen.

Ich habe auch das Scrollen gefunden viewDidAppear ein kurzes Aufblitzen der nicht gescrollten Ansicht sichtbar wird.

Wenn Sie jedes Mal viewDidLayoutSubviewseinen Bildlauf durchführen, kann der Benutzer nicht manuell einen Bildlauf durchführen, da einige Sammlungslayouts bei jedem Bildlauf ein Layout der Unteransicht verursachen.

Folgendes funktioniert zuverlässig:

Ziel c :

- (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];
    }
}

Swift:

 override func viewWillLayoutSubviews() {

    super.viewWillLayoutSubviews()

      if (!self.initialScrollDone) {

         self.initialScrollDone = true
         self.testNameCollectionView.scrollToItem(at:selectedIndexPath, at: .centeredHorizontally, animated: true)
    }

}

Netter Tipp. Ich werde die Verwendung eines initialScrollDoneFlags wie bei LenK hervorheben, da diese Methode mehrmals aufgerufen wird und wenn Sie scrollToItemAtIndexPath aufrufen: mehr als einmal scheint es die collectionView unscrollbar zu machen (iOS-Simulator iPhone 5 / iOS 8)
maz

1
Funktioniert hervorragend in iOS8. Sollte die akzeptierte Antwort sein.
Nick

5
Dies hat bei iOS 8.3 bei mir nicht funktioniert. Musste [self.collectionView layoutIfNeeded];vorher anrufen , was auch funktioniert, wenn Sie dies innerhalb tun viewDidLoad.
Brent Dillingham

1
Dies sollte definitiv die akzeptierte Antwort sein. Die obige Antwort gab mir einen Blitz, als die erste Zelle angezeigt und dann mit meiner neuen Zelle aktualisiert wurde. Diese Methode geht nahtlos über.
simon_smiley

Dies funktioniert auch unter iOS 9 und bringt mein automatisches Layout nicht durcheinander.
Herr Zystem

168

Neue, bearbeitete Antwort:

Fügen Sie dies hinzu viewDidLayoutSubviews

SCHNELL

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

Normalerweise .centerVerticallyist das der Fall

ObjC

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

Alte Antwort für älteres iOS

Fügen Sie dies hinzu in viewWillAppear:

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

4
Genau das versuche ich zu verwenden. Ich habe die Nummer des Objekts im Array und kenne den Namen dieses Objekts. Aber Sie wissen nicht, wie Sie den richtigen indexPath setzen sollen ... Irgendwelche Ideen?
AlexanderZ

4
Sie können leicht erstellen indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
Boweidmann

3
Hatte einige Fehler. Aber dann habe ich den gesamten erwähnten Code in (void) viewDidLayoutSubviews {} eingefügt und jetzt funktioniert es einwandfrei. Vielen Dank Bogdan.
AlexanderZ

1
Wie kann ich in die Zelle hineinzoomen und sie vergrößert anzeigen?
Fatuhoku

9
Dies funktioniert unter iOS 7.1 nicht zuverlässig und kann dazu führen, dass die Sammlungsansicht als schwarzer Bildschirm angezeigt wird. Ich wollte auch nicht den Status wie die Lösung in viewDidLayoutSubviews unten beibehalten. Was ich getan habe, ist einfach ein [self.view layoutIfNeeded] direkt vor dem Aufruf von scrollToItemAtIndexPath
Daniel Galasko

15

Ich stimme der obigen Antwort voll und ganz zu. Das einzige ist, dass für mich die Lösung den Code in viewDidAppear gesetzt hat

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

Als ich viewWillAppear verwendet habe, hat das Scrollen nicht funktioniert.


2
viewDidAppear hat den Nachteil, dass sich die Sammlungsansicht bewegt / blinkt, die Ansicht bereits angezeigt wurde (wie der Name schon sagt) ... Ich frage mich wirklich, warum Apple diesen nicht so ungewöhnlichen Fall nicht schöner gestaltet hat, wie es bei viewDidLayoutSubviews der Fall ist ein bisschen umständlich
TheEye

12

Dies schien für mich zu funktionieren, es ähnelt einer anderen Antwort, weist jedoch einige deutliche Unterschiede auf:

- (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];
}

12

Schnell:

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

Swift 3

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

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

Bildlaufposition:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically

9

Sie können GCD verwenden, um den Bildlauf in die nächste Iteration der Hauptlaufschleife in viewDidLoad zu senden, um dieses Verhalten zu erreichen. Der Bildlauf wird ausgeführt, bevor die Sammlungsansicht auf dem Bildschirm angezeigt wird, sodass kein Blinken erfolgt.

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

Wie bekomme ich einen Indexpfad, wenn Position 3 ist?
Kemdo

5

Ich würde empfehlen, dies in zu tun. collectionView: willDisplay:Dann können Sie sicher sein, dass der Delegat der Sammlungsansicht etwas liefert. Hier mein Beispiel:

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
    }
}

1
Ich fand, dass die Verwendung von didEndDisplaying anstelle von willDisplay der Weg war, um dies richtig zum Laufen zu bringen. willDisplay war in Ordnung, solange sich die Zelle auf dem Bildschirm befand. Wenn die Zelle jedoch noch nicht auf dem Bildschirm angezeigt wurde, hat mich diese Methode nicht dorthin gescrollt. didEndDisplaying funktionierte jedoch perfekt für diesen Anwendungsfall. Schätzen Sie Ihre Antwort und bringen Sie mich auf den richtigen Weg!
C6Silver

2

Als Alternative zu den oben genannten. Aufruf nach dem Laden der Daten:

Schnell

collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .right)

1

Alle Antworten hier - Hacks. Ich habe einen besseren Weg gefunden, um die Sammlungsansicht irgendwo nach relaodData zu scrollen:
Layout der Unterklassen-Sammlungsansicht, welches Layout auch immer Sie verwenden, überschreiben Sie die Methode prepareLayout, und legen Sie nach dem Superaufruf fest, welchen Versatz Sie benötigen.
Beispiel: https://stackoverflow.com/a/34192787/1400119

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.