วิธีการตรวจหาจุดสิ้นสุดของการโหลด UITableView


141

ฉันต้องการเปลี่ยนออฟเซ็ตของตารางเมื่อโหลดเสร็จและออฟเซ็ตขึ้นอยู่กับจำนวนของเซลล์ที่โหลดบนตาราง

มันอยู่บน SDK หรือไม่ที่จะรู้ว่าเมื่อการโหลด uitableview เสร็จสิ้นหรือไม่ ฉันไม่เห็นอะไรเลยทั้งในผู้รับมอบสิทธิ์และในแหล่งข้อมูลโปรโตคอล

ฉันไม่สามารถใช้จำนวนแหล่งข้อมูลได้เนื่องจากการโหลดของเซลล์ที่มองเห็นได้เท่านั้น


ลองการรวมกันของแหล่งข้อมูลนับและ 'indexPathsForVisibleRows'
Swapnil Luktuke

1
เปิดอีกครั้งตามข้อมูลเพิ่มเติมในการตั้งค่าสถานะ: "มันไม่ซ้ำกันมันถามเกี่ยวกับการโหลดของเซลล์ที่มองเห็นไม่เกี่ยวกับเสร็จสิ้นการถามข้อมูลดูการอัปเดตเพื่อตอบรับที่ยอมรับ"
Kev

วิธีนี้ใช้ได้ผลดีสำหรับฉัน คุณตรวจสอบแล้วstackoverflow.com/questions/1483581/…
Khaled Annajar

คำตอบ:


224

ปรับปรุงคำตอบ @RichX: lastRowสามารถเป็นได้ทั้งหรือ[tableView numberOfRowsInSection: 0] - 1 ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).rowดังนั้นรหัสจะเป็น:

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([indexPath row] == ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row){
        //end of loading
        //for example [activityIndicator stopAnimating];
    }
}

ปรับปรุง: ดีความคิดเห็นของ @ htafoya ถูกต้อง หากคุณต้องการให้รหัสนี้ตรวจจับการโหลดข้อมูลทั้งหมดจากแหล่งที่มามันจะไม่เกิดขึ้น แต่นั่นไม่ใช่คำถามเดิม รหัสนี้ใช้สำหรับการตรวจจับเมื่อแสดงเซลล์ทั้งหมดที่ต้องการให้มองเห็นได้ willDisplayCell:ใช้ที่นี่เพื่อ UI ที่ราบรื่นขึ้น (เซลล์เดียวมักแสดงผลเร็วหลังการwillDisplay:โทร) tableView:didEndDisplayingCell:นอกจากนี้คุณยังสามารถลองกับ


ดีกว่ามากสำหรับการรู้เมื่อโหลดเซลล์ทั้งหมดที่มองเห็นได้
Eric

14
อย่างไรก็ตามสิ่งนี้จะถูกเรียกเมื่อผู้ใช้เลื่อนเพื่อดูเซลล์เพิ่มเติม
htafoya

ปัญหาเกี่ยวกับสิ่งนี้คือมันไม่ได้คำนึงถึงมุมมองส่วนท้าย อาจไม่เป็นปัญหาสำหรับคนส่วนใหญ่ แต่ถ้าเป็นเช่นนั้นคุณสามารถใช้ความคิดเดียวกัน แต่ในviewForFooterInSectionวิธีการ
Kyle Clegg

1
@KyleClegg patric.schenke ได้กล่าวถึงหนึ่งในเหตุผลในการแสดงความคิดเห็นต่อคำตอบของคุณ นอกจากนี้จะเกิดอะไรขึ้นถ้าส่วนท้ายไม่ปรากฏในตอนท้ายของการโหลดเซลล์?
folex

27
tableView: didEndDisplayingCell: จริง ๆ แล้วถูกเรียกเมื่อลบเซลล์ออกจากมุมมองไม่ใช่เมื่อการเรนเดอร์ในมุมมองเสร็จสมบูรณ์ดังนั้นจึงไม่ทำงาน ไม่ใช่ชื่อวิธีที่ดี ต้องอ่านเอกสาร
Andrew Raphael

34

รุ่น Swift 3 & 4 & 5:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let lastVisibleIndexPath = tableView.indexPathsForVisibleRows?.last {
        if indexPath == lastVisibleIndexPath {
            // do here...
        }
    }
}

1
วิธีนี้ถูกเรียกเมื่อเราทำการโหลดข้อมูลครั้งแรก ในกรณีของฉันมีเซลล์ที่มองเห็นได้เพียง 4 เซลล์เท่านั้น ฉันโหลดแถวที่ 8 แต่ยังคงมีการเรียกใช้ฟังก์ชันนี้ สิ่งที่ฉันต้องการคือการโหลดข้อมูลเพิ่มเติมเมื่อผู้ใช้เลื่อนลงไปที่แถวสุดท้าย
Muhammad Nayab

สวัสดีมูฮัมหมัดนายาบบางทีคุณอาจแทนที่ "if indexPath == lastVisibleIndexPath" ด้วย "if indexPath.row == yourDataSource.count"
Daniele Ceglia

1
@DanieleCeglia ขอบคุณสำหรับการชี้จุดนี้ if indexPath == lastVisibleIndexPath && indexPath.row == yourDataSource.count - 1 สิ่งนี้จะใช้ได้กับฉัน ไชโย !!!
Yogesh Patel

28

ฉันมักจะใช้วิธีแก้ปัญหาง่ายๆนี้เสมอ:

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([indexPath row] == lastRow){
        //end of loading
        //for example [activityIndicator stopAnimating];
    }
}

วิธีการตรวจสอบแถวสุดท้าย? นั่นเป็นปัญหาสำหรับฉัน .. คุณช่วยอธิบายได้อย่างไรว่าคุณจะได้รับสิ่งนั้นในสภาพนั้นได้อย่างไร
Sameera Chathuranga

6
แถวสุดท้ายคือ[tableView numberOfRowsInSection: 0] - 1. คุณต้องแทนที่0ด้วยค่าที่ต้องการ แต่นั่นไม่ใช่ปัญหา ปัญหาคือว่าโหลด UITableView มองเห็นได้เท่านั้น อย่างไรก็ตามการ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).rowแก้ปัญหา
folex

1
หากเรากำลังมองหาการทำให้เสร็จสมบูรณ์จะไม่เป็นการดีที่สุดที่จะใช้ - (void) tableView: (UITableView *) tableView didEndDisplayingCell: เซลล์ (UITableViewCell *) forRowAtIndexPath: (NSIndexPath *) indexPath?
morcutt

10

นี่เป็นอีกตัวเลือกที่ใช้งานได้สำหรับฉัน ในวิธีมอบสิทธิ์ viewForFooter ตรวจสอบว่าเป็นส่วนสุดท้ายและเพิ่มรหัสของคุณหรือไม่ วิธีการนี้มาถึงใจหลังจากที่ทราบว่า willDisplayCell ไม่ได้คำนึงถึงส่วนท้ายหากคุณมี

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section 
{
  // Perform some final layout updates
  if (section == ([tableView numberOfSections] - 1)) {
    [self tableViewWillFinishLoading:tableView];
  }

  // Return nil, or whatever view you were going to return for the footer
  return nil;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
  // Return 0, or the height for your footer view
  return 0.0;
}

- (void)tableViewWillFinishLoading:(UITableView *)tableView
{
  NSLog(@"finished loading");
}

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


กลับมาnilจากความtableView:viewForFooterInSection:ยุ่งเหยิงกับเค้าโครงของฉันใน iOS 7 โดยใช้เค้าโครงอัตโนมัติ
ma11hew28

น่าสนใจ เกิดอะไรขึ้นถ้าคุณตั้งเป็นเฟรมที่มีความสูงและความกว้าง 0 return CGRectMake(0,0,0,0);
Kyle Clegg

self.tableView.sectionFooterHeight = 0ฉันพยายามที่และแม้กระทั่งชุด ดูเหมือนว่าจะแทรกมุมมองท้ายกระดาษของส่วนที่มีความสูงประมาณ 10 ฉันคิดว่าฉันสามารถแก้ไขได้ด้วยการเพิ่มข้อ จำกัด ความสูง 0 ถึงมุมมองที่ฉันกลับมา อย่างไรก็ตามฉันดีเพราะฉันต้องการทราบวิธีเริ่มต้น UITableView ในเซลล์สุดท้ายแต่เห็นสิ่งนี้ก่อน
ma11hew28

1
@MattDiPasquale หากคุณใช้ viewForFooterInSection คุณต้องใช้ heightForFooterInSection ด้วย มันจะต้องส่งคืน 0 สำหรับส่วนที่มีส่วนท้ายของศูนย์ นี่คือเอกสารอย่างเป็นทางการในตอนนี้
patric.schenke

viewForFooterInSection จะไม่ถูกเรียกถ้าคุณตั้งค่า heightForFooterInSection เป็น 0
Oded Harth

10

โซลูชัน Swift 2:

// willDisplay function
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    let lastRowIndex = tableView.numberOfRowsInSection(0)
    if indexPath.row == lastRowIndex - 1 {
        fetchNewDataFromServer()
    }
}

// data fetcher function
func fetchNewDataFromServer() {
    if(!loading && !allDataFetched) {
        // call beginUpdates before multiple rows insert operation
        tableView.beginUpdates()
        // for loop
        // insertRowsAtIndexPaths
        tableView.endUpdates()
    }
}

9

ใช้ API ส่วนตัว:

@objc func tableViewDidFinishReload(_ tableView: UITableView) {
    print(#function)
    cellsAreLoaded = true
}

ใช้ public API:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // cancel the perform request if there is another section
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(tableViewDidLoadRows:) object:tableView];

    // create a perform request to call the didLoadRows method on the next event loop.
    [self performSelector:@selector(tableViewDidLoadRows:) withObject:tableView afterDelay:0];

    return [self.myDataSource numberOfRowsInSection:section];
}

// called after the rows in the last section is loaded
-(void)tableViewDidLoadRows:(UITableView*)tableView{
    self.cellsAreLoaded = YES;
}

การออกแบบที่ดีกว่าที่เป็นไปได้คือการเพิ่มเซลล์ที่มองเห็นลงในชุดจากนั้นเมื่อคุณต้องการตรวจสอบว่าตารางถูกโหลดคุณสามารถทำการวนรอบรอบชุดนี้ได้หรือไม่

var visibleCells = Set<UITableViewCell>()

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    visibleCells.insert(cell)
}

override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    visibleCells.remove(cell)
}

// example property you want to show on a cell that you only want to update the cell after the table is loaded. cellForRow also calls configure too for the initial state.
var count = 5 {
    didSet {
        for cell in visibleCells {
            configureCell(cell)
        }
    }
}

ทางออกที่ดีกว่าคนอื่นมาก ไม่จำเป็นต้องโหลด tableView อีกครั้ง มันง่ายมากและ viewDidLoadRows: จะไม่ถูกเรียกใช้ทุกครั้งที่โหลดเซลล์สุดท้าย
Matt Hudson

นี่เป็นทางออกที่ดีที่สุดจนถึงขณะนี้เนื่องจากโซลูชันอื่น ๆ ไม่ได้คำนึงถึงหลาย ๆ ส่วน
Justicepenny

ฉันขอโทษสำหรับความคิดเห็นที่น่าสะอิดสะเอียน แต่ 'วิเศษ' นี้เป็นอย่างไรกันแน่? โทรออกไปยังวิธีอื่นจากตัวแทน ฉันไม่เข้าใจ
Lukas Petr

@ LukasPetr ดูที่การยกเลิกและ afterDelay ผู้ที่เปิดใช้งานวิธีการที่จะถูกยกเลิกสำหรับทุกส่วนยกเว้นที่ผ่านมาซึ่งเมื่อตารางโหลดเสร็จสมบูรณ์
2560

@ อิมัลชันโอ้ไม่เป็นไร มันฉลาดกว่าที่ฉันคิดไว้เล็กน้อยในตอนแรก
Lukas Petr

8

สำหรับรุ่นคำตอบที่เลือกใน Swift 3:

var isLoadingTableView = true

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if tableData.count > 0 && isLoadingTableView {
        if let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows, let lastIndexPath = indexPathsForVisibleRows.last, lastIndexPath.row == indexPath.row {
            isLoadingTableView = false
            //do something after table is done loading
        }
    }
}

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


6

วิธีที่ดีที่สุดที่ฉันรู้คือคำตอบของ Eric ที่: รับการแจ้งเตือนเมื่อ UITableView ร้องขอข้อมูลเสร็จแล้วหรือไม่

อัปเดต: เพื่อให้ใช้งานได้ฉันต้องวางสายเหล่านี้ -tableView:cellForRowAtIndexPath:

[tableView beginUpdates];
[tableView endUpdates];

สำหรับสิ่งที่คุ้มค่าฉันใช้วิธีนี้ง่าย ๆ กับโครงการของฉันเป็นเวลาหลายเดือนและทำงานได้อย่างสมบูรณ์แบบ
Eric MORAND

3

หากต้องการทราบว่าเมื่อมุมมองตารางเสร็จสิ้นการโหลดเนื้อหาเราจำเป็นต้องมีความเข้าใจพื้นฐานเกี่ยวกับวิธีการใส่มุมมองบนหน้าจอ

ในวงจรชีวิตของแอพมีช่วงเวลาสำคัญ 4 ช่วง:

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

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

ดังนั้นฉันคิดว่าคุณกำลังเผชิญกับกรณีเช่นนี้:

tableView.reloadData()
tableView.visibleCells.count // wrong count oO

เกิดอะไรขึ้นที่นี่?

เช่นเดียวกับมุมมองใด ๆ มุมมองตารางจะโหลดเนื้อหาใหม่อย่างเกียจคร้าน ที่จริงแล้วถ้าคุณโทรreloadDataหลายครั้งมันจะไม่สร้างปัญหาด้านประสิทธิภาพ มุมมองตารางจะคำนวณขนาดเนื้อหาใหม่โดยยึดตามการนำไปปฏิบัติของผู้ได้รับมอบหมายและรอสักครู่เพื่อโหลดเซลล์ เวลานี้เรียกว่าการผ่านเลย์เอาต์

โอเควิธีผ่านเลย์เอาต์

ในระหว่างการจัดวางผังแอพจะคำนวณเฟรมทั้งหมดของลำดับชั้นการดู การมีส่วนร่วม, คุณสามารถแทนที่วิธีการทุ่มเทlayoutSubviews, updateLayoutConstraintsฯลฯ ในUIViewและวิธีการที่เทียบเท่าใน subclass มุมมองควบคุม

นั่นคือสิ่งที่มุมมองของตารางทำ มันแทนที่layoutSubviewsและขึ้นอยู่กับการดำเนินงานของผู้ได้รับมอบหมายของคุณเพิ่มหรือลบเซลล์ มันโทรได้cellForRowทันทีก่อนที่จะเพิ่มและจัดโครงร่างเซลล์ใหม่willDisplayทันที หากคุณเรียกreloadDataหรือเพิ่มมุมมองตารางไปยังลำดับชั้นมุมมองตารางจะเพิ่มจำนวนเซลล์ตามที่จำเป็นเพื่อเติมเฟรมในช่วงเวลาที่สำคัญนี้

เอาล่ะ แต่ตอนนี้จะรู้ได้อย่างไรเมื่อมุมมองตารางเสร็จสิ้นการโหลดเนื้อหาใหม่

ตอนนี้เราสามารถเรียบเรียงคำถามใหม่อีกครั้ง: จะรู้ได้อย่างไรเมื่อมุมมองตารางเสร็จสิ้นการจัดวางหัวข้อย่อยแล้ว?

วิธีที่ง่ายที่สุดคือเข้าไปในเลย์เอาต์ของมุมมองตาราง:

class MyTableView: UITableView {
    func layoutSubviews() {
        super.layoutSubviews()
        // the displayed cells are loaded
    }
}

โปรดทราบว่าวิธีนี้เรียกว่าหลายครั้งในวงจรชีวิตของมุมมองตาราง เนื่องจากการเลื่อนและลักษณะการทำงาน dequeue ของมุมมองตารางเซลล์จะถูกแก้ไขลบและเพิ่มบ่อยครั้ง แต่ใช้งานได้หลังจากsuper.layoutSubviews()โหลดเซลล์แล้ว โซลูชันนี้เทียบเท่ากับรอwillDisplayเหตุการณ์ของพา ธ ดัชนีล่าสุด เหตุการณ์นี้เรียกว่าในระหว่างการดำเนินการของlayoutSubviewsมุมมองตารางสำหรับแต่ละเซลล์ที่เพิ่ม

อีกวิธีหนึ่งคือการได้รับการเรียกเมื่อแอปเสร็จสิ้นเลย์เอาต์

ตามที่อธิบายไว้ในเอกสารคุณสามารถใช้ตัวเลือกของUIView.animate(withDuration:completion):

tableView.reloadData()
UIView.animate(withDuration: 0) {
    // layout done
}

โซลูชันนี้ใช้งานได้ แต่หน้าจอจะรีเฟรชหนึ่งครั้งระหว่างช่วงเวลาที่จัดวางและเวลาที่บล็อกถูกเรียก สิ่งนี้เทียบเท่ากับDispatchMain.asyncโซลูชัน แต่ระบุไว้

อีกทางเลือกหนึ่งฉันต้องการบังคับเค้าโครงของมุมมองตาราง

มีวิธีการเฉพาะเพื่อบังคับให้มุมมองใด ๆ ในการคำนวณทันทีเฟรมย่อยของมันlayoutIfNeededคือ:

tableView.reloadData()
table.layoutIfNeeded()
// layout done

อย่างไรก็ตามโปรดระวังการทำเช่นนี้จะลบการโหลดแบบสันหลังยาวที่ระบบใช้ การเรียกวิธีการเหล่านั้นซ้ำ ๆ อาจสร้างปัญหาประสิทธิภาพการทำงาน ตรวจสอบให้แน่ใจว่าจะไม่ถูกเรียกก่อนเฟรมของมุมมองตารางมิฉะนั้นมุมมองตารางจะถูกโหลดอีกครั้งและคุณจะไม่ได้รับแจ้ง


ฉันคิดว่าไม่มีวิธีแก้ปัญหาที่สมบูรณ์แบบ คลาส Subclassing อาจนำไปสู่ ​​trubles เลย์เอาต์ผ่านเริ่มต้นจากด้านบนและไปด้านล่างดังนั้นจึงไม่ง่ายที่จะได้รับการแจ้งเตือนเมื่อเลย์เอาต์ทั้งหมดเสร็จสิ้น และlayoutIfNeeded()สามารถสร้างปัญหาด้านประสิทธิภาพการทำงาน ฯลฯ แต่เมื่อรู้ว่าตัวเลือกเหล่านั้นคุณควรจะสามารถคิดได้ในอีกทางเลือกหนึ่งที่เหมาะสมกับความต้องการของคุณ


1

นี่คือวิธีที่คุณทำใน Swift 3:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if indexPath.row == 0 {
        // perform your logic here, for the first row in the table
    }

    // ....
}

1

นี่คือวิธีที่ฉันทำใน Swift 3

let threshold: CGFloat = 76.0 // threshold from bottom of tableView

internal func scrollViewDidScroll(_ scrollView: UIScrollView) {

    let contentOffset = scrollView.contentOffset.y
    let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;

    if  (!isLoadingMore) &&  (maximumOffset - contentOffset <= threshold) {
        self.loadVideosList()
    }
}

1

นี่คือสิ่งที่ฉันจะทำ

  1. ในคลาสพื้นฐานของคุณ (สามารถเป็น rootVC BaseVc เป็นต้น)

    A. เขียนโพรโทคอลเพื่อส่งการเรียกกลับ "DidFinishReloading"

    @protocol ReloadComplition <NSObject>
    @required
    - (void)didEndReloading:(UITableView *)tableView;
    @end

    B. เขียนวิธีการทั่วไปเพื่อโหลดมุมมองตารางอีกครั้ง

    -(void)reloadTableView:(UITableView *)tableView withOwner:(UIViewController *)aViewController;
  2. ในการใช้งานวิธีการเรียนระดับพื้นฐานโทร reloadData ตามด้วย delegateMethod ด้วยความล่าช้า

    -(void)reloadTableView:(UITableView *)tableView withOwner:(UIViewController *)aViewController{
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [tableView reloadData];
            if(aViewController && [aViewController respondsToSelector:@selector(didEndReloading:)]){
                [aViewController performSelector:@selector(didEndReloading:) withObject:tableView afterDelay:0];
            }
        }];
    }
  3. ยืนยันกับโปรโตคอลการโหลดซ้ำในตัวควบคุมมุมมองทั้งหมดที่คุณต้องการติดต่อกลับ

    -(void)didEndReloading:(UITableView *)tableView{
        //do your stuff.
    }

การอ้างอิง: https://discussions.apple.com/thread/2598339?start=0&tstart=0


0

@ คำตอบแบบยืดหยุ่นถูกต้อง

แต่จะล้มเหลวหาก tableView มีการแสดงมากกว่าหนึ่งส่วนในเวลาเดียวกัน

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
   if([indexPath isEqual:((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject])]){
    //end of loading

 }
}

0

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

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

0

ฉันรู้ว่านี่คือคำตอบฉันแค่เพิ่มคำแนะนำ

ตามเอกสารดังต่อไปนี้

https://www.objc.io/issues/2-concurrency/thread-safe-class-design/

การแก้ไขปัญหาเรื่องเวลาด้วย dispatch_async เป็นความคิดที่ไม่ดี ฉันขอแนะนำให้เราจัดการกับสิ่งนี้โดยเพิ่ม FLAG หรืออะไรก็ได้


0

หากคุณมีหลายส่วนต่อไปนี้เป็นวิธีรับแถวสุดท้ายในส่วนสุดท้าย (Swift 3):

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let visibleRows = tableView.indexPathsForVisibleRows, let lastRow = visibleRows.last?.row, let lastSection = visibleRows.map({$0.section}).last {
        if indexPath.row == lastRow && indexPath.section == lastSection {
            // Finished loading visible rows

        }
    }
}

0

ค่อนข้างฉันบังเอิญชนกับวิธีแก้ปัญหานี้:

tableView.tableFooterView = UIView()
tableViewHeight.constant = tableView.contentSize.height

คุณต้องตั้งค่า footerView ก่อนรับ contentSize เช่นใน viewDidLoad Btw การตั้งค่า footeView ให้คุณลบตัวคั่น "ไม่ได้ใช้"


-1

คุณกำลังมองหาจำนวนรายการทั้งหมดที่จะแสดงในตารางหรือจำนวนรายการทั้งหมดที่ปรากฏอยู่ในปัจจุบันหรือไม่ ไม่ว่าจะด้วยวิธีใดก็ตามฉันเชื่อว่าวิธีการ 'viewDidLoad' จะเรียกใช้งานหลังจากที่มีการเรียกเมธอดแหล่งข้อมูลทั้งหมด อย่างไรก็ตามสิ่งนี้จะใช้ได้กับการโหลดครั้งแรกของข้อมูลเท่านั้น (หากคุณใช้ ViewController ในการจัดสรรครั้งเดียว)


-1

ฉันกำลังคัดลอกรหัสของ Andrew และขยายไปยังบัญชีสำหรับกรณีที่คุณมี 1 แถวในตาราง มันใช้งานได้แล้วสำหรับฉัน!

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
// detect when all visible cells have been loaded and displayed
// NOTE: iOS7 workaround used - see: http://stackoverflow.com/questions/4163579/how-to-detect-the-end-of-loading-of-uitableview?lq=1
NSArray *visibleRows = [tableView indexPathsForVisibleRows];
NSIndexPath *lastVisibleCellIndexPath = [visibleRows lastObject];
BOOL isPreviousCallForPreviousCell = self.previousDisplayedIndexPath.row + 1 == lastVisibleCellIndexPath.row;
BOOL isLastCell = [indexPath isEqual:lastVisibleCellIndexPath];
BOOL isFinishedLoadingTableView = isLastCell && ([tableView numberOfRowsInSection:0] == 1 || isPreviousCallForPreviousCell);

self.previousDisplayedIndexPath = indexPath;

if (isFinishedLoadingTableView) {
    [self hideSpinner];
}
}

หมายเหตุ: ฉันแค่ใช้ 1 ส่วนจากรหัสของ Andrew ดังนั้นโปรดจำไว้ว่า ..


ยินดีต้อนรับสู่ SO @ jpage4500 ฉันได้แก้ไขคำตอบของคุณเพื่อลบสิ่งที่เกี่ยวกับคะแนนตัวแทนต่ำและคำถามชน การขยายคำตอบของผู้ใช้รายอื่นเป็นคำตอบที่ถูกต้องสมบูรณ์แบบด้วยตัวเองดังนั้นคุณสามารถลดความยุ่งเหยิงได้โดยปล่อยสิ่งนั้นออก เป็นเรื่องดีที่คุณให้เครดิตกับแอนดรูว์
skrrgwasme

-3

ใน iOS7.0x การแก้ปัญหาแตกต่างกันเล็กน้อย นี่คือสิ่งที่ฉันมาด้วย

    - (void)tableView:(UITableView *)tableView 
      willDisplayCell:(UITableViewCell *)cell 
    forRowAtIndexPath:(NSIndexPath *)indexPath
{
    BOOL isFinishedLoadingTableView = [self isFinishedLoadingTableView:tableView  
                                                             indexPath:indexPath];
    if (isFinishedLoadingTableView) {
        NSLog(@"end loading");
    }
}

- (BOOL)isFinishedLoadingTableView:(UITableView *)tableView 
                         indexPath:(NSIndexPath *)indexPath
{
    // The reason we cannot just look for the last row is because 
    // in iOS7.0x the last row is updated before
    // looping through all the visible rows in ascending order 
    // including the last row again. Strange but true.
    NSArray * visibleRows = [tableView indexPathsForVisibleRows];   // did verify sorted ascending via logging
    NSIndexPath *lastVisibleCellIndexPath = [visibleRows lastObject];
    // For tableviews with multiple sections this will be more complicated.
    BOOL isPreviousCallForPreviousCell = 
             self.previousDisplayedIndexPath.row + 1 == lastVisibleCellIndexPath.row;
    BOOL isLastCell = [indexPath isEqual:lastVisibleCellIndexPath];
    BOOL isFinishedLoadingTableView = isLastCell && isPreviousCallForPreviousCell;
    self.previousDisplayedIndexPath = indexPath;
    return isFinishedLoadingTableView;
}

-3

วัตถุประสงค์ C

[self.tableView reloadData];
[self.tableView performBatchUpdates:^{}
                              completion:^(BOOL finished) {
                                  /// table-view finished reload
                              }];

รวดเร็ว

self.tableView?.reloadData()
self.tableView?.performBatchUpdates({ () -> Void in

                            }, completion: { (Bool finished) -> Void in
                                /// table-view finished reload
                            })

1
วิธีนี้ใช้ได้เฉพาะUICollectionViewเท่าที่ฉันเข้าใจเท่านั้น
Awesome-o

ใช่คุณถูก. UUpableView startUpdates นั้นเท่ากับ UICollectionView ของ performBatchUpdates: เสร็จสมบูรณ์ stackoverflow.com/a/25128583/988169
pkc456

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