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!

Son Nguyen
sumber

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.

Ajay
sumber
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")
    }
}
neoneye
sumber
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");
    }
}
Bola mata
sumber
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");
    }
}
8suhas
sumber
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
    }
}
Iftach Orr
sumber
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 :

Wolfgang Schreurs
sumber
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.

Anomie
sumber
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

pengguna1641587
sumber
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")
        }
}
Jay Mayu
sumber
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!")
    }
}
footyapps27
sumber
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");
    }
}
Shaik Riyaz
sumber
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
}
samwize
sumber
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
        }
    }
Morshed Alam
sumber
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];
    }
}
pohon cemara
sumber
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")
    }
}
Ibrahim
sumber
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.

Mayuri R Talaviya
sumber
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
    }
Anuran Barman
sumber