UICollectionView, IndexPath'deki hücreye otomatik kaydırma


101

Koleksiyon görünümünü yüklemeden önce kullanıcı, koleksiyon görünümü dizisindeki resim sayısını ayarlar. Tüm hücreler ekrana sığmıyor. Ekranda 30 hücre ve sadece 6 hücrem var.

Soru: UICollectionView yükünde istenen görüntüye sahip hücreye otomatik olarak nasıl kaydırılır?

Yanıtlar:


91

viewWillAppearKoleksiyon görünümü henüz düzenini bitirmediği için içeri kaydırmanın güvenilir bir şekilde çalışmayabileceğini fark ettim; yanlış öğeye kaydırabilirsiniz.

Ayrıca, kaydırmanın viewDidAppear, kaydırılmamış görünümün anlık bir flaşının görünür olmasına neden olacağını buldum .

Ayrıca, her seferinde kaydırırsanız viewDidLayoutSubviews, bazı koleksiyon düzenleri her kaydırdığınızda alt görünüm düzenine neden olacağından, kullanıcı el ile kaydırma yapamaz.

İşte bulduğum şey güvenilir bir şekilde çalışıyor:

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

}

Güzel ipucu. Bir kullanarak vurgulamak edeceğiz initialScrollDonedaha o CollectionView'ın unscrollable içerir hale görünüyor defadan (iOS simülatörü iPhone 8 5 / iOS): Bu yöntem birden fazla kez ve scrollToItemAtIndexPath ararsanız denilen olsun çünkü Lenk yaptığı gibi bayrak
maz

1
İOS8'de harika çalışıyor. Kabul edilen cevap olmalı.
Nick

5
Bu benim için iOS 8.3'te çalışmadı. Daha [self.collectionView layoutIfNeeded];önce aramak zorunda kaldı, bu da bunu içinde yaptığınızda işe yarıyor viewDidLoad.
Brent Dillingham

1
Bu kesinlikle kabul edilen cevap olmalıdır. Yukarıdaki cevap, ilk hücre gösterildiğinde ve ardından yeni hücremle güncellendiğinde bana bir flaş verdi, bu yöntem sorunsuz bir şekilde geçiş yapıyor.
simon_smiley

bu aynı zamanda iOS 9'da da çalışır ve ayrıca otomatik düzenimi bozmaz.
Bay Zystem

169

Yeni, Düzenlenmiş Cevap:

Bunu şuraya ekle viewDidLayoutSubviews

SWIFT

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

Normalde .centerVerticallydurum böyledir

ObjC

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

Eski iOS için çalışan eski yanıt

Bunu şuraya ekle viewWillAppear:

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

4
Ben de tam olarak bunu kullanmaya çalışıyorum. Dizideki nesnenin numarasına sahibim ve bu nesnenin adını biliyorum. Ama doğru indexPath'i nasıl koyacağımı bilmiyorum ... Herhangi bir fikir?
AlexanderZ

4
Kolayca oluşturabilirsiniz indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
boweidmann

3
Bazı hatalar oldu. Ama sonra bahsedilen tüm kodu (void) viewDidLayoutSubviews {} içine koydum ve şimdi sorunsuz çalışıyor. Thanx Bogdan.
AlexanderZ

1
Hücreyi nasıl 'yakınlaştırabilirim' ve büyütülmüş olarak gösterebilirim?
fatuhoku

9
Bu, iOS 7.1'de güvenilir bir şekilde çalışmaz ve koleksiyon görünümünün siyah ekran olarak görünmesine neden olabilir. Ayrıca aşağıdaki viewDidLayoutSubviews çözümündeki gibi durumu korumak istemedim. Yaptığım şey, scrollToItemAtIndexPath çağrısından hemen önce bir [self.view layoutIfNeeded] gerçekleştirdi
Daniel Galasko

16

Yukarıdaki cevaba tamamen katılıyorum. Tek şey, benim için çözümün kodu viewDidAppear'da ayarlamasıydı.

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

ViewWillAppear'ı kullandığımda kaydırma çalışmadı.


2
viewDidAppear, koleksiyon görünümünün hareket ettiğini / yanıp söndüğünü görmeniz dezavantajına sahiptir, görünüm zaten ortaya çıkmıştır (adından da anlaşılacağı gibi) ... Apple'ın bu kadar alışılmadık bir durumu neden daha hoş bir şekilde tasarlamadığını gerçekten merak ediyorum, viewDidLayoutSubviews yolu biraz garip
TheEye

12

bu benim için işe yaramış gibi görünüyordu, başka bir yanıta benziyor ancak bazı belirgin farklılıkları var:

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

Swift:

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

Hızlı 3

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

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

Kaydırma Konumu:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically

9

Bu davranışı elde etmek için, kaydırmayı viewDidLoad'daki ana çalıştırma döngüsünün sonraki yinelemesine göndermek için GCD'yi kullanabilirsiniz. Kaydırma, toplama görünümü ekranda gösterilmeden önce gerçekleştirilecektir, bu nedenle yanıp sönme olmayacaktır.

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

konum 3 olduğunda dizin yolu nasıl alınır?
kemdo

5

Bunu içinde collectionView: willDisplay:yapmanızı tavsiye ederim. O zaman koleksiyon görünümü temsilcisinin bir şeyler verdiğinden emin olabilirsiniz. İşte örneğim:

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
Bunun düzgün çalışmasını sağlamanın willDisplay yerine didEndDisplaying kullanmanın yolu olduğunu buldum. willDisplay, hücre ekranda olduğu sürece tamamdı; ancak, hücre henüz ekranda değilse, bu yöntem beni ona kaydırmadı. didEndDisplaying, bu kullanım durumu için mükemmel bir şekilde çalıştı. Cevabınız beni doğru yola koyduğunuz için teşekkür ederiz!
C6Silver

2

Yukarıda bahsedilenlere bir alternatif olarak. Veri yüklendikten sonra ara:

Swift

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

1

Buradaki tüm cevaplar - hackler. RelaodData'dan sonra koleksiyon görünümünü kaydırmanın daha iyi bir yolunu buldum: Kullandığınız
düzen ne olursa olsun, alt sınıf koleksiyon görünümü düzeni, süper çağrı ayarından sonra ihtiyacınız olan ofseti ayarlayın.
ör: https://stackoverflow.com/a/34192787/1400119

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.