-
-
Save johndelong/ed4a7e2a8161f73c7548f74bb9b6f1bd to your computer and use it in GitHub Desktop.
// | |
// ViewController.swift | |
// Example | |
// | |
// Created by John DeLong on 5/11/16. | |
// Copyright © 2016 delong. All rights reserved. | |
// | |
import UIKit | |
extension Date { | |
func dateFromDays(_ days: Int) -> Date { | |
return (Calendar.current as NSCalendar).date(byAdding: .day, value: days, to: self, options: [])! | |
} | |
} | |
class ViewController: UIViewController { | |
@IBOutlet weak var tableView: UITableView! | |
let cellBuffer: CGFloat = 2 | |
let cellHeight: CGFloat = 44 | |
let daysToAdd = 30 | |
let dateFormatter = DateFormatter() | |
lazy var days: [Date] = { | |
let beginDate = Date().dateFromDays(-29) | |
let endDate = Date().dateFromDays(30) | |
return self.generateDays(beginDate, endDate: endDate) | |
}() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.tableView.delegate = self | |
self.tableView.dataSource = self | |
self.dateFormatter.dateFormat = "MM-dd-yyyy" | |
} | |
func generateDays(_ beginDate: Date, endDate: Date) -> [Date] { | |
var dates: [Date] = [] | |
var date = beginDate | |
while date.compare(endDate) != .orderedDescending { | |
dates.append(date) | |
date = date.dateFromDays(1) | |
} | |
return dates | |
} | |
} | |
extension ViewController: UITableViewDataSource { | |
func numberOfSections(in tableView: UITableView) -> Int { | |
return 1 | |
} | |
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return self.days.count | |
} | |
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let cell = UITableViewCell() | |
cell.textLabel!.text = self.dateFormatter.string(from: self.days[(indexPath as NSIndexPath).row]) | |
return cell | |
} | |
} | |
extension ViewController: UITableViewDelegate { | |
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { | |
return self.cellHeight; | |
} | |
func scrollViewDidScroll(_ scrollView: UIScrollView) { | |
let top: CGFloat = 0 | |
let bottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height | |
let buffer: CGFloat = self.cellBuffer * self.cellHeight | |
let scrollPosition = scrollView.contentOffset.y | |
// Reached the bottom of the list | |
if scrollPosition > bottom - buffer { | |
// Add more dates to the bottom | |
let lastDate = self.days.last! | |
let additionalDays = self.generateDays(lastDate.dateFromDays(1), endDate: lastDate.dateFromDays(self.daysToAdd)) | |
self.days.append(contentsOf: additionalDays) | |
self.days.removeFirst(self.daysToAdd) | |
// Update the tableView and contentOffset | |
self.tableView.reloadData() | |
self.tableView.contentOffset.y -= CGFloat(self.daysToAdd) * self.cellHeight | |
} | |
// Reach the top of the list | |
else if scrollPosition < top + buffer { | |
// Add more dates to the top | |
let firstDate = self.days.first! | |
let additionalDates = self.generateDays(firstDate.dateFromDays(-self.daysToAdd), endDate: firstDate.dateFromDays(-1)) | |
self.days.insert(contentsOf: additionalDates, at: 0) | |
self.days.removeLast(self.daysToAdd) | |
// Update the tableView and contentOffset | |
tableView.reloadData() | |
self.tableView.contentOffset.y += CGFloat(self.daysToAdd) * self.cellHeight | |
} | |
} | |
} |
This gist was very helpful for me to understand how to implement Infinite scrolling. Thank You!
For infinite scroll up, how would you calculate the contentOffset for the tableview, if the newly added cells have dynamic height?
When run this code with paging enabled (each cell occupying whole page), the offset change applied at end of data manipulation is lost. So when the code comes back to compare scroll again, the data change situation will be triggered again, making scroll jump by numToAdd each time. If we separate the data changes and apply only one each time, be it remove or append, the offset change will be carried over and scroll will work perfectly.
Run this with Xcode 10.2, Swift 5. Not sure whether the author or anybody else has seen similar problem.
This works if there are no sections. I'd like to know how you would approach a table that has sections with differing numbers of rows per section.