จะรู้ได้อย่างไรว่าเมื่อ UITableView เลื่อนไปที่ด้านล่างของ iPhone


101

ฉันต้องการทราบว่าเมื่อUITableViewใดเลื่อนไปด้านล่างเพื่อโหลดและแสดงเนื้อหาเพิ่มเติมบางอย่างเช่นผู้รับมอบสิทธิ์หรืออย่างอื่นเพื่อแจ้งให้ผู้ควบคุมทราบเมื่อตารางเลื่อนไปด้านล่าง

มีใครรู้บ้างโปรดช่วยฉันด้วยขอบคุณล่วงหน้า!

คำตอบ:


19

วิธีที่ดีที่สุดคือทดสอบจุดที่ด้านล่างของหน้าจอและใช้วิธีนี้เรียกเมื่อผู้ใช้เลื่อน ( scrollViewDidScroll):

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

ทดสอบจุดที่อยู่ใกล้ด้านล่างสุดของหน้าจอจากนั้นใช้ indexPath ซึ่งจะส่งกลับให้ตรวจสอบว่า indexPath เป็นแถวสุดท้ายหรือไม่ให้เพิ่มแถว


น่าเสียดายที่แอพของฉันจะอัปเดตข้อมูลแบบเรียลไทม์สำหรับแถวที่มีอยู่ในตารางนี้ดังนั้นวิธีนี้อาจได้รับเนื้อหาเพิ่มเติมเมื่อตารางไม่เลื่อนเลย
Son Nguyen

247

ใน tableview delegate ทำสิ่งนี้

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

รวดเร็ว:

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

ดี! เพียงใช้: y> = h + reload_distance ซึ่งเป็นปัญหาเฉพาะเมื่อ reload_distance = 0 (เช่นสำหรับการตีกลับ NO)
Chris Prince

4
รหัสนี้ใน "scrollViewDidScroll" ถูกเรียกใช้งานตลอดเวลาที่ผู้ใช้เลื่อนนิ้วขึ้น / ลงบนหน้าจอ จะดีกว่าถ้าย้ายไปไว้ใน "scrollViewDidEndDecelerating" วิธีนี้จะดำเนินการหนึ่งครั้งเมื่อผู้ใช้หยุดขยับนิ้ว
Misha

อืม .. รหัสนี้ยังใช้ได้ไหม ไม่ได้รับด้านล่างของ UITableView สำหรับฉัน ฉันหวังว่าฉันจะรู้เหตุผลเบื้องหลังโค้ดทั้งหมดข้างต้นเพื่อที่ฉันจะได้แก้ไข
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 getting false
Abhishek Thapliyal

62

นีนีนีย์ดัดแปลงตอบหน่อย

คำตอบนี้มีเป้าหมายที่บรรดาผู้ที่ต้องการเพียงเหตุการณ์ที่จะถูกเรียกครั้งเดียวต่อการเปิดตัวของนิ้วมือ

เหมาะสำหรับการโหลดเนื้อหาเพิ่มเติมจากผู้ให้บริการเนื้อหาบางราย (บริการเว็บข้อมูลหลัก ฯลฯ ) โปรดทราบว่าแนวทางนี้ไม่เคารพเวลาตอบกลับจากบริการบนเว็บของคุณ

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

วิธีนี้ใช้ไม่ได้ เมื่อใดก็ตามที่ผู้ใช้เลื่อนลงไปด้านล่างระบบจะเรียก "โหลดแถวเพิ่มเติม" สิ่งนี้เกิดขึ้นแม้ว่าผู้ใช้จะเลื่อนไปด้านล่างแล้วและกำลังรอให้ API ส่งคืนข้อมูล
คณบดี

2
คณบดีคำถามเกี่ยวกับการรู้ว่าเมื่อใดที่มุมมองตารางเลื่อนไปด้านล่าง คุณกำลังดึงข้อมูลจาก API หรือไม่ไม่เกี่ยวข้องใช่หรือไม่
Eyeball

แต่ไม่มีข้อความแสดง load more .. เพื่อให้ผู้ใช้ทราบว่ามีผลลัพธ์ที่จะแสดงมากขึ้น
iPhone 7

คำตอบที่ดีในกรณีของฉันมันใช้งานได้ถ้า: float reload_distance = 10; ถ้า (y> (h - reload_distance)) {NSLog (@ "โหลดแถวเพิ่มเติม"); } เพราะ y = 565 และ h ยังเป็น 565
Abhishek Thapliyal

1
ฉันลองทั้งคำตอบของ Eyeball และ @neoneye เชื่อฉันหรือไม่ 'scrollViewDidScroll' ถูกเรียกหลายครั้งเทียบกับ 'scrollViewDidEndDragging' ดังนั้นการใช้ 'scrollViewDidEndDragging' จึงมีประสิทธิภาพเนื่องจากฉันมีการเรียกใช้ API
Vinod Supnekar

39

เพิ่มวิธีนี้ใน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
ฉันชอบโซลูชันนี้ยกเว้นรายละเอียดเล็ก ๆ อย่างเดียว if (distanceFromBottom <= height)
Mark McCorkle

สิ่งนี้ช่วยฉันแก้ไขปัญหาของฉันขอบคุณ !! แถบแท็บ !! มันเป็นแถบแท็บโง่ !!
Dmytro

งานนี้เหมือนมีเสน่ห์และมันก็เรียบง่ายเช่นกัน แต่ฉันกำลังเผชิญปัญหาเล็ก ๆ อย่างหนึ่งเช่นมันกำลังดำเนินการสองหรือสามครั้งในแถวสุดท้าย จะทำให้มันดำเนินการเพียงครั้งเดียวเมื่อถึงแถวสุดท้ายของ tableview?
อาร์โมฮัน

ขอบคุณมาก!! ฉันใส่รหัสนี้ใน scrollViewWillBeginDecelerating และดำเนินการเพียงครั้งเดียวเมื่อเลื่อนไปที่แถวสุดท้าย
Manali

20

ไม่มีคำตอบใดข้างต้นช่วยฉันได้ดังนั้นฉันจึงได้สิ่งนี้:

- (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" มาจากไหน
ainesophaur

นี่คือมุมมองแบบเลื่อนไม่ใช่ตาราง
iosMentalist

19

ใช้– tableView:willDisplayCell:forRowAtIndexPath:( UITableViewDelegateวิธีการ)

เพียงเปรียบเทียบindexPathกับรายการในอาร์เรย์ข้อมูลของคุณ (หรือแหล่งข้อมูลใด ๆ ที่คุณใช้สำหรับมุมมองตารางของคุณ) เพื่อดูว่าองค์ประกอบสุดท้ายกำลังแสดงอยู่หรือไม่

เอกสาร: http://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:willDisplayCell:forRowAtIndexPath :


จากนั้นหากคุณโหลดข้อมูลของ tableView ซ้ำคุณจะติดอยู่ในวงวนไม่สิ้นสุด
Dielson Sales

14

UITableViewเป็น subclass ของUIScrollViewและสอดรับไปUITableViewDelegate UIScrollViewDelegateดังนั้นผู้รับมอบสิทธิ์ที่คุณแนบไปกับมุมมองตารางจะได้รับเหตุการณ์เช่นscrollViewDidScroll:และคุณสามารถเรียกใช้เมธอดต่างๆเช่นcontentOffsetบนมุมมองตารางเพื่อค้นหาตำแหน่งการเลื่อน


ใช่นั่นคือสิ่งที่ฉันกำลังมองหาโดยใช้ผู้รับมอบสิทธิ์นั้นและตรวจสอบว่าตำแหน่งการเลื่อนเป็น UITableViewScrollPositionBottom หรือไม่ฉันจะรู้ว่าเมื่อตารางเลื่อนไปที่ด้านล่างขอบคุณมาก
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];

สวยและเรียบง่าย


8

ในSwiftที่ที่คุณสามารถทำอะไรเช่นนี้ เงื่อนไขต่อไปนี้จะเป็นจริงทุกครั้งที่คุณไปถึงจุดสิ้นสุดของ tableview

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

1
ปัญหาคือเมื่อ tableview มีเพียง 3 เซลล์เช่นprintln("came to last row")โค้ดนี้ทำงาน!
Mc.Lover

@ Mc.Lover นั่นเป็นปัญหาที่แน่นอนสำหรับฉันสำหรับการใช้งาน CPU ที่จะไปถึง 92% คำตอบของนีนี่ย์ใช้ได้ผลสำหรับฉัน ฉันยังเพิ่มเวอร์ชั่นที่รวดเร็วหากคุณต้องการ
Anuran Barman

7

จากคำตอบของ @Jay Mayu ซึ่งฉันรู้สึกว่าเป็นหนึ่งในวิธีแก้ปัญหาที่ดีกว่า:

วัตถุประสงค์ -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!");
  }
}

สวิฟต์ 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

โดยทั่วไปฉันจะใช้สิ่งนี้เพื่อโหลดข้อมูลเพิ่มเติมเมื่อเซลล์สุดท้ายเริ่มแสดงผล

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

1
มันผิด ทุกครั้งที่คุณเรียกใช้ reloadData จะมีการร้องขอ และบางครั้งคุณก็ต้องโหลดตารางใหม่
Patrick Bassut

คุณอยากจะบอกว่าถ้าคุณอยู่ในเซลล์สุดท้ายแล้วทำการรีโหลดข้อมูลสิ่งนี้จะเกิดขึ้น?
Shaik Riyaz

5

การneoneyeคำตอบที่ดี แต่ในความรวดเร็วและเปลี่ยนชื่อของตัวแปร ..

โดยทั่วไปเราทราบดีว่าเรามาถึงด้านล่างสุดของมุมมองตารางแล้วหากส่วนyOffsetAtBottomสูงเกินความสูงของเนื้อหาตาราง

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

นี่คือรหัสเวอร์ชันที่รวดเร็ว 3.0

   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

วิธีแก้ปัญหาของฉันคือเพิ่มเซลล์ก่อนที่ tableview จะชะลอตัวลงเมื่อชดเชยโดยประมาณ มันสามารถคาดเดาได้ด้วยความเร็ว

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

คำตอบของ Neoneye ทำงานได้ดีที่สุดสำหรับฉันใน Objective C ซึ่งเทียบเท่ากับคำตอบใน 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

ฉันต้องการดำเนินการบางอย่างกับ Tableviewcell 1 ตัวเต็มของฉัน

ดังนั้นรหัสจึงเชื่อมโยง:

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

ขอให้สิ่งนี้ช่วยได้บ้าง


0

คำตอบของ @ neoneye ใช้ได้ผลสำหรับฉัน นี่คือเวอร์ชันSwift 4

    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
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.