UITableView'ün iPhone'da ne zaman aşağıya kaydığını nasıl anlarım?


101

Daha UITableViewfazla içerik yüklemek ve göstermek için ne zaman aşağı kaydırdığını bilmek istiyorum, bir temsilci gibi bir şey veya denetleyiciye tablonun ne zaman en alta kaydığını bildirmek için başka bir şey.

Bunu bilen var mı, lütfen bana yardım edin, şimdiden teşekkürler!

Yanıtlar:


19

En iyi yol, ekranın altındaki bir noktayı test etmek ve kullanıcı kaydırdığında bu yöntem çağrısını kullanmaktır ( scrollViewDidScroll):

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

Ekranın altına yakın bir noktayı test edin ve sonra geri dönen indexPath'i kullanarak indexPath'in son satır olup olmadığını kontrol edin ve eğer öyleyse satır ekleyin.


Maalesef, Uygulamam bu tablodaki mevcut satırlar için verileri gerçek zamanlı olarak güncelleyecektir, bu nedenle tablo hiç kaydırılmadığında bu şekilde daha fazla içerik elde edilebilir.
Son Nguyen

247

tablo görünümünde delege böyle bir şey yapın

ObjC:

- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
    CGPoint offset = aScrollView.contentOffset;
    CGRect bounds = aScrollView.bounds;
    CGSize size = aScrollView.contentSize;
    UIEdgeInsets inset = aScrollView.contentInset;
    float y = offset.y + bounds.size.height - inset.bottom;
    float h = size.height;
    // NSLog(@"offset: %f", offset.y);   
    // NSLog(@"content.height: %f", size.height);   
    // NSLog(@"bounds.height: %f", bounds.size.height);   
    // NSLog(@"inset.top: %f", inset.top);   
    // NSLog(@"inset.bottom: %f", inset.bottom);   
    // NSLog(@"pos: %f of %f", y, h);

    float reload_distance = 10;
    if(y > h + reload_distance) {
        NSLog(@"load more rows");
    }
}

Swift:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offset = scrollView.contentOffset
    let bounds = scrollView.bounds
    let size = scrollView.contentSize
    let inset = scrollView.contentInset
    let y = offset.y + bounds.size.height - inset.bottom
    let h = size.height
    let reload_distance:CGFloat = 10.0
    if y > (h + reload_distance) {
        print("load more rows")
    }
}

İyi! Sadece şunu kullanın: y> = h + reload_distance, bu gerçekten yalnızca reload_distance = 0 olduğunda bir endişe kaynağıdır (örneğin, sıçrama HAYIR için).
Chris Prince

4
"ScrollViewDidScroll" içindeki bu kod, kullanıcı parmağını ekranda yukarı / aşağı hareket ettirdiğinde her zaman yürütülür. "ScrollViewDidEndDecelerating" altına taşımak daha iyidir. Bu şekilde, kullanıcı parmağını hareket ettirmeyi bıraktığında bir kez çalıştırılacaktır.
Misha

hmm .. bu kod hala çalışıyor mu? benim için UITableView'ın altını almıyor. Keşke yukarıdaki tüm kodun arkasındaki sebebi bilseydim, belki düzeltebilirim
FlowUI. SimpleUITesting.com

ofset: 237.000000 content.height: 855.000000 bounds.height: 667.000000 inset.top: 64.000000 inset.bottom: 49.000000 pos: 855.000000 of 855.000000 yanlış
oluyorsa

62

Değiştirilmiş neoneyler biraz cevap veriyor.

Bu cevap, olayın parmaklarının her serbest bırakılmasında yalnızca bir kez tetiklenmesini isteyenleri hedef alır .

Bazı içerik sağlayıcılardan (web hizmeti, temel veriler vb.) Daha fazla içerik yüklerken uygundur. Bu yaklaşımın web hizmetinizin yanıt süresine uymadığını unutmayın.

- (void)scrollViewDidEndDragging:(UIScrollView *)aScrollView
                  willDecelerate:(BOOL)decelerate
{
    CGPoint offset = aScrollView.contentOffset;
    CGRect bounds = aScrollView.bounds;
    CGSize size = aScrollView.contentSize;
    UIEdgeInsets inset = aScrollView.contentInset;
    float y = offset.y + bounds.size.height - inset.bottom;
    float h = size.height;

    float reload_distance = 50;
    if(y > h + reload_distance) {
        NSLog(@"load more rows");
    }
}

Bu çalışmıyor. Kullanıcı aşağıya kaydırdığında, "daha fazla satır yükle" çağrılır. Bu, kullanıcı zaten aşağı kaydırmış ve API'nin veri döndürmesini beklemiş olsa bile gerçekleşir.
Dean

2
Dean, soru tablo görünümünün ne zaman aşağıya kaydırıldığını bilmekle ilgiliydi. Bir API'den veri alıyor olmanız veya almamanız önemli değil, değil mi?
Eyeball

Ancak daha fazla yükleme gösteren bir mesaj yok .. böylece kullanıcı gösterilecek daha fazla sonuç olduğunu fark edebilir.
iPhone 7

Benim durumumda güzel cevap şu durumda çalışıyor: float reload_distance = 10; eğer (y> (h - reload_distance)) {NSLog (@ "daha fazla satır yükle"); } çünkü y = 565 ve h aynı zamanda 565
Abhishek Thapliyal

1
Hem Eyeball'un hem de @neoneye'nin yanıtını denedim. Bana inanın ya da 'scrollViewDidEndDragging' ile karşılaştırıldığında birden çok kez 'scrollViewDidScroll' olarak adlandırmayın. Bu yüzden üzerinde API çağrım olduğu için 'scrollViewDidEndDragging' kullanmak verimli oldu.
Vinod Supnekar

39

bu yöntemi şuraya ekleyin UITableViewDelegate:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{   
    CGFloat height = scrollView.frame.size.height;

    CGFloat contentYoffset = scrollView.contentOffset.y;

    CGFloat distanceFromBottom = scrollView.contentSize.height - contentYoffset;

    if(distanceFromBottom < height) 
    {
        NSLog(@"end of the table");
    }
}

3
Küçük bir ayrıntı dışında bu çözümü seviyorum. eğer (distanceFromBottom <= yükseklik)
Mark McCorkle

Bu, sorunumu gidermeme yardımcı oldu, teşekkür ederim !! sekme çubuğu !! aptal bir sekme çubuğuydu !!
Dmytro

bu bir cazibe gibi çalışıyor ve aynı zamanda basit, ancak son satırda iki veya üç kez çalıştırılıyor gibi küçük bir sorunla karşı karşıyayım. tablo görünümünün son satırına ulaştığında yalnızca bir kez çalıştırılması nasıl sağlanır?
R.Mohan

Çok teşekkür ederim!! Bu kodu scrollViewWillBeginDecelerating'e koyuyorum ve son satıra kaydırıldığında yalnızca bir kez çalışıyor.
Manali

20

Yukarıdaki cevapların hiçbiri bana yardımcı olmadı, bu yüzden şunu buldum:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView
{   
    NSArray *visibleRows = [self.tableView visibleCells];
    UITableViewCell *lastVisibleCell = [visibleRows lastObject];
    NSIndexPath *path = [self.tableView indexPathForCell:lastVisibleCell];
    if(path.section == lastSection && path.row == lastRow)
    {
        // Do something here
    }
}

"LastSection" ın nereden geldiğini açıklayabilir misiniz?
ainesophaur

bu tablo için değil, kaydırma görünümü içindir
iosMentalist

19

Kullanım – tableView:willDisplayCell:forRowAtIndexPath:( UITableViewDelegateyöntem)

indexPathSon öğenin görüntülenip görüntülenmediğini anlamak için veri dizinizdeki öğelerle (veya tablo görünümünüz için kullandığınız her türlü veri kaynağını) karşılaştırmanız yeterlidir .

Dokümanlar: http://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:willDisplayCell:forRowAtIndexPath :


Ardından, tableView verilerini yeniden yüklerseniz, sonsuz bir döngüde kalacaksınız.
Dielson Satışları

14

UITableViewalt sınıfıdır UIScrollViewve UITableViewDelegateuyumludur UIScrollViewDelegate. Dolayısıyla, tablo görünümüne eklediğiniz temsilci scrollViewDidScroll:, gibi olayları alır contentOffsetve kaydırma konumunu bulmak için tablo görünümündeki gibi yöntemleri çağırabilirsiniz .


Evet, aradığım şey bu, bu temsilciyi uygulayarak ve kaydırma konumunun UITableViewScrollPositionBottom olup olmadığını kontrol ederek, tablonun ne zaman aşağıya kaydırıldığını bileceğim, çok teşekkürler
Son Nguyen

8
NSLog(@"%f / %f",tableView.contentOffset.y, tableView.contentSize.height - tableView.frame.size.height);

if (tableView.contentOffset.y == tableView.contentSize.height - tableView.frame.size.height)
        [self doSomething];

Güzel ve basit


8

içinde Swiftböyle bir şey yapabilirsiniz. Tablo görünümünün sonuna her ulaştığınızda aşağıdaki koşul doğru olacaktır

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        if indexPath.row+1 == postArray.count {
            println("came to last row")
        }
}

1
sorun, tablo görünümünün yalnızca 3 hücreye sahip olduğu zamandır, örneğin println("came to last row")bu kod çalışır!
Mc.Lover

@ Mc.Lover CPU kullanımının% 92'ye çıktığı benim için tam problem buydu. neoneye'nin cevabı benim için çalıştı. İhtiyacınız olursa bunun için hızlı versiyon da ekledim.
Anuran Barman

7

@Jay Mayu'nun cevabına dayanarak, daha iyi çözümlerden biri olduğunu düşündüm:

Amaç-C

// UITableViewDelegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

// Need to call the service & update the array
if(indexPath.row + 1 == self.sourceArray.count) {
    DLog(@"Displayed the last row!");
  }
}

Swift 2.x

// UITableViewDelegate
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if (indexPath.row + 1) == sourceArray.count {
        print("Displayed the last row!")
    }
}

5

Bunu genellikle son hücre görüntülenmeye başladığında daha fazla veri yüklemek için kullanırım

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   if (indexPath.row ==  myDataArray.count-1) {
        NSLog(@"load more");
    }
}

1
Bu yanlış. ReloadData'yı her aradığınızda bir istek yapılacaktır. Ve bazen masayı yeniden yüklemeniz gerekir.
Patrick Bassut

Söylemek istediniz, eğer son hücredeyseniz ve daha sonra bir yeniden yükleme verisi yaptıysa, o zaman bu olur?
Shaik Riyaz

5

Alarak neoneye mükemmel cevaplar ama Swift içinde ve değişkenlerin yeniden adlandırma ..

Temel olarak yOffsetAtBottom, tablo içeriği yüksekliğinin ötesinde ise tablo görünümünün altına ulaştığımızı biliyoruz .

func isTableViewScrolledToBottom() -> Bool {
    let tableHeight = tableView.bounds.size.height
    let contentHeight = tableView.contentSize.height
    let insetHeight = tableView.contentInset.bottom

    let yOffset = tableView.contentOffset.y
    let yOffsetAtBottom = yOffset + tableHeight - insetHeight

    return yOffsetAtBottom > contentHeight
}

5

İşte hızlı 3.0 sürüm kodu.

   func scrollViewDidScroll(_ scrollView: UIScrollView) {

        let offset = scrollView.contentOffset
        let bounds = scrollView.bounds
        let size = scrollView.contentSize
        let inset = scrollView.contentInset
        let y: Float = Float(offset.y) + Float(bounds.size.height) + Float(inset.bottom)
        let height: Float = Float(size.height)
        let distance: Float = 10

        if y > height + distance {
            // load more data
        }
    }

3

Benim çözümüm, tablo görünümü tahmini ofset üzerinde yavaşlamadan önce hücreler eklemektir. Hızla tahmin edilebilir.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)offset {

    NSLog(@"offset: %f", offset->y+scrollView.frame.size.height);
    NSLog(@"Scroll view content size: %f", scrollView.contentSize.height);

    if (offset->y+scrollView.frame.size.height > scrollView.contentSize.height - 300) {
        NSLog(@"Load new rows when reaches 300px before end of content");
        [[DataManager shared] fetchRecordsNextPage];
    }
}

3

Swift 3 güncellemesi

Neoneye'nin cevabı benim için en iyi şekilde Objective C'de çalıştı, bu Swift 3'teki cevabın karşılığı:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let offset: CGPoint = scrollView.contentOffset
    let bounds: CGRect = scrollView.bounds
    let size: CGSize = scrollView.contentSize
    let inset: UIEdgeInsets = scrollView.contentInset
    let y: CGFloat = offset.y + bounds.size.height - inset.bottom
    let h: CGFloat = size.height
//        print("offset: %f", offset.y)
//        print("content.height: %f", size.height)
//        print("bounds.height: %f", bounds.size.height)
//        print("inset.top: %f", inset.top)
//        print("inset.bottom: %f", inset.bottom)
//        print("position: %f of %f", y, h)

    let reloadDistance: CGFloat = 10

    if (y > h + reloadDistance) {
            print("load more rows")
    }
}

2

Herhangi 1 tam Tableviewcell'imde bazı işlemler yapmak istiyorum.

Yani kod şu bağlantıdır:

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    NSArray* cells = self.tableView.visibleCells;
    NSIndexPath *indexPath = nil ;

    for (int aIntCount = 0; aIntCount < [cells count]; aIntCount++)
    {

        UITableViewCell *cell = [cells objectAtIndex:aIntCount];
CGRect cellRect = [self.tableView convertRect:cell.frame toView:self.tableView.superview];

        if (CGRectContainsRect(self.tableView.frame, cellRect))
        {
            indexPath = [self.tableView indexPathForCell:cell];

    //  remain logic
        }
     }
}

Bu birine yardım etsin.


0

@ neoneye'nin cevabı benim için çalıştı. İşte Swift 4 versiyonu

    let offset = scrollView.contentOffset
    let bounds = scrollView.bounds
    let size = scrollView.contentSize
    let insets = scrollView.contentInset
    let y = offset.y + bounds.size.height - insets.bottom
    let h = size.height
    let reloadDistance = CGFloat(10)
    if y > h + reloadDistance {
        //load more rows
    }
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.