UICollectionView menggulir otomatis ke sel di IndexPath


101

Sebelum memuat tampilan koleksi, pengguna menyetel jumlah gambar dalam larik tampilan koleksi. Semua sel tidak muat di layar. Saya memiliki 30 sel dan hanya 6 di layar.

Pertanyaannya: Bagaimana cara menggulir ke sel dengan gambar yang diinginkan secara otomatis pada beban UICollectionView?

Jawaban:


90

Saya telah menemukan bahwa pengguliran viewWillAppearmungkin tidak bekerja dengan andal karena tampilan koleksi belum menyelesaikan tata letaknya; Anda mungkin menggulir ke item yang salah.

Saya juga menemukan bahwa menggulir ke dalam viewDidAppearakan menyebabkan kilatan sesaat dari tampilan yang tidak digulirkan terlihat.

Dan, jika Anda menggulir setiap kali viewDidLayoutSubviews, pengguna tidak akan dapat menggulir secara manual karena beberapa tata letak koleksi menyebabkan tata letak subview setiap kali Anda menggulir.

Inilah yang menurut saya berfungsi dengan andal:

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

}

Tip yang bagus. Saya akan menekankan penggunaan sebuah initialScrollDonebendera seperti yang telah dilakukan LenK karena metode ini akan dipanggil lebih dari sekali dan jika Anda memanggil scrollToItemAtIndexPath: lebih dari sekali tampaknya membuat collectionView tidak dapat digulung (simulator iOS iPhone 5 / iOS 8)
maz

1
Berfungsi dengan baik di iOS8. Harus menjadi jawaban yang diterima.
Nick

5
Ini tidak berhasil untuk saya di iOS 8.3. Harus menelepon [self.collectionView layoutIfNeeded];sebelumnya, yang juga berfungsi saat Anda melakukan ini di dalam viewDidLoad.
Brent Dillingham

1
Ini pasti harus menjadi jawaban yang diterima. Jawaban di atas memberi saya kilat saat sel pertama ditampilkan dan kemudian diperbarui dengan sel baru saya, metode ini bertransisi dengan mulus.
simon_smiley

ini juga berfungsi di iOS 9, dan juga tidak mengacaukan tata letak otomatis saya.
Tn. Zystem

168

Jawaban Baru yang Diedit:

Tambahkan ini viewDidLayoutSubviews

CEPAT

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

Biasanya, .centerVerticallydemikianlah kasusnya

ObjC

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

Jawaban lama berfungsi untuk iOS lama

Tambahkan ini di viewWillAppear:

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

4
Itulah yang saya coba gunakan. Saya memiliki jumlah objek dalam array dan saya tahu nama objek itu. Tapi tidak tahu bagaimana meletakkan indexPath yang benar ... Ada ide?
AlexanderZ

4
Anda dapat dengan mudah membuat indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
boweidmann

3
Ada beberapa kesalahan. Tapi kemudian saya meletakkan semua kode yang disebutkan di dalam (void) viewDidLayoutSubviews {} dan sekarang bekerja dengan baik. Thanx Bogdan.
AlexanderZ

1
Bagaimana cara 'memperbesar' ke dalam sel, dan memperlihatkannya diperbesar?
fatuhoku

9
Ini tidak berfungsi dengan andal di iOS 7.1 dan dapat menyebabkan tampilan koleksi muncul sebagai layar hitam. Saya juga tidak ingin mempertahankan status seperti solusi di viewDidLayoutSubviews di bawah ini. Apa yang saya lakukan hanyalah melakukan [self.view layoutIfNeeded] tepat sebelum panggilan ke scrollToItemAtIndexPath
Daniel Galasko

15

Saya sangat setuju dengan jawaban di atas. Satu-satunya hal adalah bagi saya solusinya adalah mengatur kode di viewDidAppear

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

Ketika saya menggunakan viewWillAppear, pengguliran tidak berfungsi.


2
melihat sedikit canggung
TheEye

12

ini sepertinya berhasil untuk saya, ini mirip dengan jawaban lain tetapi memiliki beberapa perbedaan berbeda:

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

Cepat:

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

Cepat 3

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

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

Posisi Gulir:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically

9

Anda dapat menggunakan GCD untuk mengirimkan scroll ke iterasi berikutnya dari run loop utama di viewDidLoad untuk mencapai perilaku ini. Gulir akan dilakukan sebelum tampilan koleksi ditampilkan di layar, jadi tidak akan ada flashing.

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

bagaimana cara mendapatkan indexpath ketika posisi 3?
kemdo

5

Saya akan merekomendasikan melakukannya di. collectionView: willDisplay:Kemudian Anda dapat yakin bahwa delegasi tampilan koleksi mengirimkan sesuatu. Berikut contoh saya:

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
Saya menemukan bahwa menggunakan didEndDisplaying, alih-alih willDisplay, adalah cara untuk membuatnya berfungsi dengan benar. willDisplay baik-baik saja selama sel berada di layar; Namun, jika sel belum ada di layar, metode ini tidak menggulir saya ke sana. didEndDisplaying bekerja dengan sempurna untuk kasus penggunaan itu. Hargai jawaban Anda yang membuat saya di jalan yang benar!
C6Silver

2

Sebagai alternatif yang disebutkan di atas. Panggilan setelah pemuatan data:

Cepat

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

1

Semua jawaban di sini - peretasan. Saya telah menemukan cara yang lebih baik untuk menggulir tampilan koleksi di suatu tempat setelah relaodData:
Tata letak tampilan koleksi subkelas tata letak apa pun yang pernah Anda gunakan, timpa metode preprepLayout, setelah panggilan super mengatur apa pun yang Anda butuhkan.
mis .: https://stackoverflow.com/a/34192787/1400119

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.