UICollectionGörünür mevcut hücre dizinini görüntüleyin


115

UICollectionViewİPad uygulamamda ilk kez kullanıyorum . UICollectionViewBoyutu ve hücre boyutu aynı olacak şekilde ayarladım , yani hücrenin bir seferde yalnızca bir kez görüntülendiği anlamına gelir.

Sorun: Kullanıcı UICollectionView'i kaydırdığında, hangi hücrenin görünür olduğunu bilmem gerekiyor. Değişiklik durumunda diğer UI öğelerini güncellemem gerekiyor. Bunun için herhangi bir temsilci yöntemi bulamadım. Bunu nasıl başarabilirim?

Kod:

[self.mainImageCollection setTag:MAIN_IMAGE_COLLECTION_VIEW];
[self.mainImageCollection registerClass:[InspirationMainImageCollectionCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
[self.mainImageFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.mainImageFlowLayout setMinimumInteritemSpacing:0.0f];
[self.mainImageFlowLayout setMinimumLineSpacing:0.0f];
self.mainImageFlowLayout.minimumLineSpacing = 0;
[self.mainImageCollection setPagingEnabled:YES];
[self.mainImageCollection setShowsHorizontalScrollIndicator:NO];
[self.mainImageCollection setCollectionViewLayout:self.mainImageFlowLayout];

Ne denedim:

As UICollectionViewuygundur UIScrollView, ben aldığımda ile kullanıcı kaydırma uçları UIScrollViewDelegateyöntemle

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

Ancak yukarıdaki işlevin içinde şu anki görünür hücre indeksini nasıl alabilirim UICollectionView???


self.collectionViewFloors.indexPathsForVisibleItems
Aznix

Yanıtlar:


130

[CollectionView visibleCells] yöntemi, size istediğiniz tüm visibleCells dizisini verir. Almak istediğinizde kullanın

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    for (UICollectionViewCell *cell in [self.mainImageCollection visibleCells]) {
        NSIndexPath *indexPath = [self.mainImageCollection indexPathForCell:cell];
        NSLog(@"%@",indexPath);
    }
}

Swift 5'e güncelleme:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    for cell in yourCollectionView.visibleCells {
        let indexPath = yourCollectionView.indexPath(for: cell)
        print(indexPath)
    }
}

Self.mainImageCollection'ın nereden geldiğini biraz açıklar mısınız? Daha fazla detayınız için önceden çok teşekkürler.
Benjamin McFerren

@BenjaminMcFerren, kullandığınız koleksiyon görünümüdür.
LE SANG

10
scrollViewDidScroll:Temsilci yöntemi herhangi kaydırma bitirir (ve muhtemelen burada daha iyi bir seçimdir) ne zaman kaydırma görünümü güncellemeleri sağlar. scrollViewDidEndDecelerating:Yalnızca kaydırma görünümü " [büyük bir kaydırmadan] durma noktasına geldiğinde" çağrılan delege yönteminin aksine (bkz. UIScrollView başlığı).
Sam Spencer

1
IIRC, ..DidScrollkısa bir kaydırma sırasında bile birçok kez aranır. Ne yapmak istediğine bağlı olarak iyi bir şey olabilir veya olmayabilir.
ToolmakerSteve

4
İOS 10'dan beri artık indexPathsForVisibleItems'i doğrudan kullanmak da mümkün :)
Ben

174

indexPathsForVisibleItemsçoğu durumda işe yarayabilir, ancak bazen birden fazla dizin yoluna sahip bir dizi döndürür ve istediğinizi bulmak zor olabilir. Bu durumlarda, şöyle bir şey yapabilirsiniz:

CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];

Bu, özellikle koleksiyon görünümünüzdeki her öğe tüm ekranı kapladığında işe yarar.

Swift versiyonu

let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)

9
Katılıyorum, bazen indexPathsForVisibleItems böyle bir durumun olmaması gerektiğini düşünsek bile daha fazla hücre döndürüyor. Çözümünüz harika çalışıyor.
MP23

2
Tamamen bu tür bir durumdaydım, benim için işe yarayan sadece bir düzeltme (ancak benim durumum tableview ile oldu), CGPointMake'yi (CGRectGetMidX (visibleRect), CGRectGetMidY (visibleRect)) değiştirmem gerekiyordu; CGPointMake için (CGRectGetMidX (visibleRect), CGRectGetMinY (visibleRect));
JRafaelM

1
Mükemmel, ancak hücreler arasında boşluk varsa o visibleIndexPathzaman bazen sıfır olur, Soif (visibleIndexPath) == nil { let cells = collectionView.visibleCells() let visibleIndexPath = collectionView.indexPathForCell(cells[0] as! UICollectionViewCell)! as NSIndexPath }
Husam

Tam ekran boyutundaki hücrelerim için çalışan tek çözüm. Aşağıda cevap olarak Swift versiyonu eklendi.
Sam Bing

1
Keşke buna daha fazla oy verebilseydim. Bu sorun beni deli ediyor ve bu çözüm günü kurtardı.
SeanT

77

Swift 5 :

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    var visibleRect = CGRect()

    visibleRect.origin = collectionView.contentOffset
    visibleRect.size = collectionView.bounds.size

    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)

    guard let indexPath = collectionView.indexPathForItem(at: visiblePoint) else { return } 

    print(indexPath)
}

Swift 2.2'de Birleştirilmiş Çalışma Cevapları:

 func scrollViewDidEndDecelerating(scrollView: UIScrollView) {

        var visibleRect = CGRect()

        visibleRect.origin = self.collectionView.contentOffset
        visibleRect.size = self.collectionView.bounds.size

        let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))

        let visibleIndexPath: NSIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)

        guard let indexPath = visibleIndexPath else { return } 
        print(indexPath)

    }

Dizin yolunu iki kez alıyorum, yalnızca bir kez almam gerekiyor
Arshad Shaik

18

Bütünlük aşkına, bu benim için işe yarayan yöntemdi. @Anthony ve @ iAn'ın yöntemlerinin bir kombinasyonuydu.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
      CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
      CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
      NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
      NSLog(@"%@",visibleIndexPath);
}

11

UICollectionViewDelegate yöntemlerini kullanmak muhtemelen en iyisi olacaktır: (Swift 3)

// Called before the cell is displayed    
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    print(indexPath.row)
}

// Called when the cell is displayed
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    print(indexPath.row)
}

3
İlgili didEndDisplayingdokümanlardan,: söylerken Belirtilen hücre toplama görünümünden kaldırıldığını temsilci. Ne zaman kaybolduğunu görmek için görünümün kendisini izlemenin aksine, bir hücrenin bir koleksiyon görünümünden ne zaman kaldırıldığını algılamak için bu yöntemi kullanın. Bu yüzden didEndDisplayinghücre görüntülendiğinde çağrıldığını sanmıyorum .
Jonny

9

Sadece başkaları için eklemek istiyorum: bazı nedenlerden dolayı, pagingEnabled ile collectionView'da önceki hücreye kaydırırken kullanıcının görebildiği hücreyi alamadım.

Bu yüzden kodu dispatch_async içine biraz "hava" vermek için ekliyorum ve bu benim için çalışıyor.

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    dispatch_async(dispatch_get_main_queue(), ^{
            UICollectionViewCell * visibleCell= [[self.collectionView visibleCells] objectAtIndex:0];


            [visibleCell doSomthing];
        });
}

Bu gerçekten yardımcı oldu! Bunu kesinlikle kusursuz hale getirmek için dispatch_async bloğunu kullanabileceğimi fark etmemiştim! Bu en iyi cevap!
kalafun

1
: Swift 4 için DispatchQueue.main.async {çağrı başlatır şeyden gibifunc tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
Jonny

Bazı açıklamalar: Bu bana da yardımcı oldu ve uikollectionview içeren uitableviewcell'e geri dönerken aynı / benzer problemi yaşadım. Yenileme çağrısı willDisplay cellyukarıda belirtildiği gibi başlatıldı . Sanırım sorun, UIKit'te bir yerlerde, benim durumumda bu cevapla gerçekten aynı.
Jonny

7

Swift 3.0 için

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let visibleRect = CGRect(origin: colView.contentOffset, size: colView.bounds.size)
    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
    let indexPath = colView.indexPathForItem(at: visiblePoint)
}

6

Swift 3.0

Görünür hücreler için size indexPath verecek en basit çözüm ..

yourCollectionView.indexPathsForVisibleItems 

dizin yolu dizisini döndürür.

Bunun gibi dizideki ilk nesneyi al.

yourCollectionView.indexPathsForVisibleItems.first

Sanırım Objective - C ile de iyi çalışması gerekiyor.


6

UICollectionView mevcut görünür hücre indeksi: Swift 3

var visibleCurrentCellIndexPath: IndexPath? {
    for cell in self.collectionView.visibleCells {
        let indexPath = self.collectionView.indexPath(for: cell)
        return indexPath
     }

     return nil
}

En iyi cevap. Temiz ve birkaç satır.
garanda

1
Mükemmel cevap .. Teşekkürler
Hardik Thakkar

3

@ Anthony'nin yanıtını Swift 3.0'a dönüştürmek benim için mükemmel çalıştı:

func scrollViewDidScroll(_ scrollView: UIScrollView) {

    var visibleRect = CGRect()
    visibleRect.origin = yourCollectionView.contentOffset
    visibleRect.size = yourCollectionView.bounds.size
    let visiblePoint = CGPoint(x: CGFloat(visibleRect.midX), y: CGFloat(visibleRect.midY))
    let visibleIndexPath: IndexPath? = yourCollectionView.indexPathForItem(at: visiblePoint)
    print("Visible cell's index is : \(visibleIndexPath?.row)!")
}

2

Sen kullanabilirsiniz scrollViewDidEndDecelerating: Bunun için

//@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;

   - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{

        for (UICollectionViewCell *cell in [self.collectionView visibleCells]) {
            NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
            NSUInteger lastIndex = [indexPath indexAtPosition:[indexPath length] - 1];
            NSLog(@"visible cell value %d",lastIndex);
        }

    }

0

Bu eski bir soru ama benim durumumda ...

- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    _m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.firstObject].row;
}

- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    _m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.lastObject].row;
}

0

Ayrıca bu pasajı kontrol edin

let isCellVisible = collectionView.visibleCells.map { collectionView.indexPath(for: $0) }.contains(inspectingIndexPath)

0

Bu iş parçacığında, hücre tam ekran alırsa iyi sonuç veren pek çok çözüm var, ancak bunlar Visible rect'in koleksiyon görünümü sınırlarını ve orta noktalarını kullanıyor.Ancak bu sorunun basit bir çözümü var.

    DispatchQueue.main.async {
        let visibleCell = self.collImages.visibleCells.first
        print(self.collImages.indexPath(for: visibleCell))
    }

bununla, görünür hücrenin indexPath'ini elde edebilirsiniz. DispatchQueue ekledim çünkü daha hızlı kaydırdığınızda ve kısa bir süre için sonraki hücre gösterilirse, dispactchQueue olmadan ekranda görüntülenen hücrenin değil kısaca gösterilen hücrenin indexPath'ini alacaksınız.


-1

bunu dene, işe yarıyor. (aşağıdaki örnekte örneğin 3 hücrem var.)

    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
    let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))
    let visibleIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)
    if let v = visibleIndexPath {
        switch v.item {
        case 0: setImageDescription()
            break
        case 1: setImageConditions()
            break
        case 2: setImageResults()
            break
        default: break
        }
    }

-2

Swift 3 ve Swift 4:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
   var visibleRect = CGRect()

   visibleRect.origin = collectionView.contentOffset
   visibleRect.size = collectionView.bounds.size

   let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)

   guard let indexPath = collectionView.indexPathForItem(at: visiblePoint) else { return } 

   print(indexPath[1])
}

+1 ekleyebileceğinizden gerçek numarayı göstermek istiyorsanız

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.