Bagaimana mengetahui kapan UITableView menggulir ke bawah di iPhone


100

Saya ingin tahu kapan UITableViewmelakukan scroll ke bawah untuk memuat dan menampilkan lebih banyak konten, seperti delegasi atau sesuatu yang lain untuk memberi tahu pengontrol saat tabel melakukan scroll ke bawah.

Apakah ada yang tahu ini, tolong bantu saya, terima kasih sebelumnya!

Jawaban:


18

Cara terbaik adalah menguji suatu titik di bagian bawah layar dan menggunakan panggilan metode ini kapan pun pengguna menggulir ( scrollViewDidScroll):

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

Menguji sebuah titik di dekat bagian bawah layar, lalu menggunakan indexPath yang dikembalikannya untuk memeriksa apakah indexPath adalah baris terakhir, lalu jika ya, tambahkan baris.


Sayangnya Aplikasi saya akan memperbarui data secara real time untuk baris yang ada di tabel ini, jadi cara ini dapat memperoleh lebih banyak konten saat tabel tidak digulir sama sekali.
Son Nguyen

247

dalam delegasi tableview melakukan sesuatu seperti ini

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");
    }
}

Cepat:

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

Baik! Cukup gunakan: y> = h + reload_distance, yang benar-benar hanya menjadi perhatian saat reload_distance = 0 (misalnya, untuk bounce NO).
Chris Prince

4
Kode dalam "scrollViewDidScroll" ini dijalankan setiap saat pengguna menggerakkan jarinya ke atas / bawah di layar. Lebih baik memindahkannya ke bawah "scrollViewDidEndDecelerating". Dengan cara ini akan dijalankan sekali ketika pengguna berhenti menggerakkan jarinya.
Misha

hmm .. kode ini masih berfungsi? tidak mendapatkan bagian bawah UITableView untuk saya. Saya berharap saya tahu alasan di balik semua kode di atas jadi mungkin saya bisa memperbaikinya
FlowUI. SimpleUITesting.com

offset: 237.000000 content.height: 855.000000 bounds.height: 667.000000 inset.top: 64.000000 inset.bottom: 49.000000 pos: 855.000000 of 855.000000 if is false
Abhishek Thapliyal

62

Neoneyes yang dimodifikasi menjawab sedikit.

Jawaban ini ditujukan bagi Anda yang hanya ingin acara tersebut dipicu sekali per pelepasan jari .

Cocok saat memuat lebih banyak konten dari beberapa penyedia konten (layanan web, data inti, dll.). Perhatikan bahwa pendekatan ini tidak memperhatikan waktu respons dari layanan web Anda.

- (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");
    }
}

Ini tidak berhasil. Setiap kali pengguna menggulir ke bawah, "muat lebih banyak baris" dipanggil. Ini terjadi bahkan ketika pengguna telah menggulir ke bawah dan menunggu API mengembalikan data.
Dean

2
Dean, pertanyaannya adalah tentang mengetahui kapan tampilan tabel digulir ke bawah. Apakah Anda mengambil data dari API atau tidak itu tidak relevan, bukan?
Bola mata

Tetapi tidak ada pesan yang menunjukkan muat lebih .. sehingga pengguna dapat mengetahui bahwa ada lebih banyak hasil untuk ditampilkan.
iPhone 7

Jawaban bagus dalam kasus saya ini berfungsi jika: float reload_distance = 10; if (y> (h - reload_distance)) {NSLog (@ "muat lebih banyak baris"); } karena y = 565 dan h juga 565
Abhishek Thapliyal

1
Saya mencoba jawaban Eyeball dan @neoneye. Percaya atau tidak 'scrollViewDidScroll' dipanggil beberapa kali dibandingkan dengan 'scrollViewDidEndDragging'. Jadi itu efisien untuk menggunakan 'scrollViewDidEndDragging' karena saya memiliki panggilan API di atasnya.
Vinod Supnekar

39

tambahkan metode ini di 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
Saya suka solusi ini kecuali satu detail kecil. if (distanceFromBottom <= height)
Mark McCorkle

Ini membantu saya memecahkan masalah saya, terima kasih !! sebuah tab bar !! itu adalah tab bar bodoh !!
Dmytro

ini bekerja seperti pesona, dan itu juga sederhana, tetapi saya menghadapi satu masalah kecil seperti itu dijalankan dua atau tiga kali pada baris terakhir. bagaimana membuatnya hanya dieksekusi satu kali ketika mencapai baris terakhir tableview?
R. Mohan

Terima kasih banyak!! Saya meletakkan kode ini di scrollViewWillBeginDecelerating dan hanya dijalankan sekali saat di-scroll ke baris terakhir.
Manali

20

Tak satu pun dari jawaban di atas membantu saya, jadi saya menemukan ini:

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

Bisakah Anda menjelaskan dari mana "lastSection" berasal?
ainesophaur

ini untuk tampilan gulir dan bukan tabel
iosMentalist

19

Gunakan – tableView:willDisplayCell:forRowAtIndexPath:( UITableViewDelegatemetode)

Cukup bandingkan indexPathdengan item dalam larik data Anda (atau sumber data apa pun yang Anda gunakan untuk tampilan tabel Anda) untuk mengetahui apakah elemen terakhir sedang ditampilkan.

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


Kemudian, jika Anda memuat ulang data tableView, Anda akan terjebak dalam putaran tak terbatas.
Penjualan Dielson

14

UITableViewadalah subkelas dari UIScrollView, dan UITableViewDelegatesesuai dengan UIScrollViewDelegate. Jadi delegasi yang Anda lampirkan ke tampilan tabel akan mendapatkan peristiwa seperti scrollViewDidScroll:, dan Anda dapat memanggil metode seperti contentOffsetpada tampilan tabel untuk menemukan posisi gulir.


Ya, itulah yang saya cari, dengan mengimplementasikan delegasi itu dan memeriksa apakah posisi gulir UITableViewScrollPositionBottom, saya akan tahu ketika tabel digulir ke bawah, terima kasih banyak
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];

Bagus dan sederhana


8

di dalam Swiftkamu bisa melakukan sesuatu seperti ini. Kondisi berikut akan benar setiap kali Anda mencapai akhir tampilan tabel

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

1
masalahnya adalah ketika tableview hanya memiliki 3 sel misalnya println("came to last row")kode ini berjalan!
Mc.Lover

@ Mc.Lover itu adalah masalah yang sebenarnya bagi saya dimana penggunaan CPU akan menjadi 92%. Jawaban neoneye berhasil untuk saya. Saya juga menambahkan versi cepat untuk itu jika Anda membutuhkannya.
Anuran Barman

7

Berdasarkan jawaban @Jay Mayu, yang menurut saya adalah salah satu solusi yang lebih baik:

Objective-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!");
  }
}

Cepat 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

Saya biasanya menggunakan ini untuk memuat lebih banyak data, saat sel terakhir mulai ditampilkan

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

1
ini salah. Setiap kali Anda memanggil reloadData, permintaan akan dibuat. Dan terkadang Anda hanya perlu memuat ulang tabel.
Patrick Bassut

Anda ingin mengatakan, jika Anda di sel terakhir dan kemudian melakukan reload data maka ini akan terjadi?
Shaik Riyaz

5

Mengambil tidak ada jawaban yang sangat baik tetapi dengan cepat, dan mengganti nama variabel ..

Pada dasarnya kita tahu bahwa kita telah mencapai bagian bawah tampilan tabel jika yOffsetAtBottommelebihi tinggi konten tabel.

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

Ini adalah kode versi 3.0 swift.

   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

Solusi saya adalah menambahkan sel sebelum tampilan tabel akan melambat pada perkiraan offset. Ini bisa diprediksi dengan kecepatan.

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

Pembaruan untuk Swift 3

Jawaban Neoneye bekerja paling baik untuk saya di Tujuan C, ini setara dengan jawaban di Swift 3:

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

Saya ingin melakukan beberapa tindakan pada 1 Tableviewcell lengkap saya.

Jadi kodenya adalah link:

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

Semoga ini membantu seseorang.


0

@ Jawaban neoneye berhasil untuk saya. Ini adalah versi Swift 4 -nya

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