How to use skeleton loading with multiple sections in swift? - ios

I want to apply skeleton animation with tableview. To achieve this I am using 'SkeletonView' cocopods and it's working fine with single section but when I am trying with multiple section it's throwing out of bounds error. Even i don't know from where I could find documentation for this cocopods. If anybody has some idea please help me out.
import UIKit
import SkeletonView
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var data = [[String: Any]]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 80
tableView.estimatedRowHeight = 80
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
self.data.append(["day": "Mon",
"record": [
["name": "Abhya"], ["name": "Anivesh"]
]
])
self.data.append(["day": "Tue",
"record": [
["name": "Vivek"], ["name": "Arun"]
]
])
self.data.append(["day": "Wed",
"record": [
["name": "Bindu"], ["name": "Aliya"]
]
])
self.data.append(["day": "Thi",
"record": [
["name": "Vivek"], ["name": "Arun"]
]
])
print(self.data[0])
self.tableView.stopSkeletonAnimation()
self.view.hideSkeleton()
self.tableView.reloadData()
})
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.isSkeletonable = true
tableView.showAnimatedGradientSkeleton()
tableView.showAnimatedSkeleton(usingColor: .concrete, transition: .crossDissolve(0.25))
}
func getArray(withDictionary array: Any?) -> [Dictionary<String, Any>] {
guard let arr = array as? [Dictionary<String, Any>] else {
return []
}
return arr
}
}
extension ViewController:UITableViewDelegate {
}
extension ViewController: SkeletonTableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
self.data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let dictionary = self.data[section]
let array = getArray(withDictionary: dictionary["record"])
return array.count
}
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier {
return "TeacherCell"
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell") as! HeaderTableViewCell
print("section", section)
let dict = self.data[section]
cell.dayName.text = dict["day"] as! String
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TeacherCell") as! TeacherTableViewCell
let dictionary = self.data[indexPath.row]
let array = getArray(withDictionary: dictionary["record"])
let dict = array[indexPath.row]
cell.teacherName.text = dictionary["name"] as! String
return cell
}
}

I had the same issue and solved it in the tableView Cell.
In awakeNib() add: someLabel.showAnimatedSkeleton()
After that add a custom function:
func hideSkeleton(){
someLabel.hideSkeleton()
}
Now in Your MainView Controller call this function in cellForItem just before return cell.
Hope this works for you.

Related

Swift 5 - Set TextLabel in Custom CollectionviewCell from JSON Array

I have created a custom cell for my collectionview that i have set in a tableview for my app. I need to know to to set the text label to appear as the items in my array that is listed in my JSON File that is local.
View Controller:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var workoutData = [Models]()
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
parseJSON()
tableview.register(CollectionTableViewCell.nib(), forCellReuseIdentifier: CollectionTableViewCell.identifier)
print(workoutData)
}
func numberOfSections(in tableView: UITableView) -> Int {
return workoutData.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return workoutData[section].title
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return workoutData[section].workouts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CollectionTableViewCell.identifier, for: indexPath) as! CollectionTableViewCell
cell.configure(with: workoutData)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableview.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 250.0
}
func parseJSON() {
let url = Bundle.main.url(forResource: "data", withExtension: "json")!
do{
let data = try Data(contentsOf: url)
workoutData = try JSONDecoder().decode([Models].self, from: data)
} catch {
print(error)
}
}
}
My Custom Cell File:
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
var workoutData = [Models]()
#IBOutlet weak var myLabel: UILabel!
static let identifier = "MyCollectionViewCell"
static func nib() -> UINib {
return UINib(nibName: "MyCollectionViewCell", bundle: nil)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
public func configure(with model: Models) {
self.myLabel.text = //what to put here.
print(model.title)
}
}
My JSON File:
[
{
"title": "Chest",
"workouts": [
"Bench",
"Pushup",
"Incline Press",
"Decline Press",
]
},
{
"title": "Back",
"workouts": [
"Barbell Row",
"Lat Pulldown",
"Deadlift",
"Back Extension",
]
},
{
"title": "Arms",
"workouts": [
"Barbell Curl",
"Dumbbell Curl",
"Tricep Pressdown",
"Skull Crusher",
]
}
]
I want my text label to show the items in my workouts array. when i set it i get the error "cannot assign value of type '[String]' to type 'String'". I would appreciate any help or directions. Thanks
EDIT:
I am looking to build my layout similar to the horizontal scroll of the the app store
workouts is an array of String. So firstly you need to get the String from array by index.
You can use this to show the first value on the label
self.myLabel.text = models.workouts[0]
Or If you want to show all the workouts values on the array then you can use
self.myLabel.text = models.workouts.joined(separator: ", ")

Outputting element from two-dimensional array from separate class

I need to output the second element from a two-dimensional array from one class to a TableViewController. I've tried a couple things, such as data.reduce into:, with no luck. The FirstViewController is supposed to be populated with the three genres "Action, Suspense and Romance", which can then be clicked on to show all the movies that belong to that genre.
First Class:
import Foundation
protocol MovieModelDelegate: class {
func didRecieveDataUpdate(data: [[String]])
}
class MovieModel {
weak var delegate: MovieModelDelegate?
var genreArray: [String] = []
let data: [[String]] = [
["Avatar", "Action"],
["Limitless", "Suspense"],
["Die Hard", "Action"],
["The Avengers", "Action"],
["The Notebook", "Romance"],
["Lakehouse", "Romance"],
["Gone Girl", "Suspense"],
["Deadpool", "Action"],
["Passengers", "Suspense"],
["Inception", "Suspense"],
["Mission Impossible", "Action"]
]
func requestData() {
let movie: [[String]] = data
delegate?.didRecieveDataUpdate(data: movie)
}
}
**TableView Class:**
class FirstTableView: UITableViewController, MovieModelDelegate {
var model = MovieModel()
var selectedGenre: String = ""
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.genreArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenreCells", for: indexPath) as! TableViewCell
cell.genreLabel?.text = model.genreArray[indexPath.item]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedGenre = model.data[indexPath.row]
selectedGenre = ""
for indexPath in model.data{
if indexPath[1] == selectedGenre{
selectedGenre.append(indexPath[0])
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "pushToMovies") {
if let VC = segue.destination as? FilteredSelection {
VC.selectedMovies = [selectedGenre]
}
}
}
func didRecieveDataUpdate(data: [[String]]) {
}
deinit{
}
}
You need to change the data into a form that can then be indexed by a tableview. I would change it into a dictionary using the following code.
let genreDictionary = data.reduce(into: [:]) { d, element in
d[element[1], default: []].append(element[0])
}
This will create the following Dictionary
["Suspense": ["Limitless", "Gone Girl", "Passengers", "Inception"],
"Romance": ["The Notebook", "Lakehouse"],
"Action": ["Avatar", "Die Hard", "The Avengers", "Deadpool", "Mission Impossible"]]
Then in your tableview functions you use the dictionary as follows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.genreDictionary.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenreCells", for: indexPath) as! TableViewCell
let d = model.genreDictionary
cell.genreLabel?.text = d[d.keys.index(d.startIndex, offsetBy: indexPath.row)].key
return cell
}
When you need the array of films for a certain tableview row you can use the following
let d = model.genreDictionary
let arrayOfFilms = d[d.keys.index(d.startIndex, offsetBy: indexPath.row)].value
You can use a Set to get all Genres without to have duplicates.
I recognized you want to display the genres in your TableView with model.genreArray but your genreArray is always empty because you never append data to it.
The second thing I recoginzed: In your TableViewController you
implemented the didReciveDataUpdate function, but you didnt do
anything with it.
First Class:
import Foundation
protocol MovieModelDelegate: class {
func didRecieveDataUpdate(data: [[String]])
}
class MovieModel {
weak var delegate: MovieModelDelegate?
let data: [[String]] = [
["Avatar", "Action"],
["Limitless", "Suspense"],
["Die Hard", "Action"],
["The Avengers", "Action"],
["The Notebook", "Romance"],
["Lakehouse", "Romance"],
["Gone Girl", "Suspense"],
["Deadpool", "Action"],
["Passengers", "Suspense"],
["Inception", "Suspense"],
["Mission Impossible", "Action"]
]
private var genres = [String]()
public init() {
for dataSet in data {
self.genres.append(dataSet[1])
}
//this will generate a array with only uniqe genres
var genreArray = Array(Set(self.genres))
}
func requestData() {
let movie: [[String]] = data
delegate?.didRecieveDataUpdate(data: movie)
}
}
FirstTableView Class:
(view didReciveDataUpdate function)
class FirstTableView: UITableViewController, MovieModelDelegate {
var model = MovieModel()
var selectedGenre: String = ""
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.genreArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenreCells", for: indexPath) as! TableViewCell
cell.genreLabel?.text = model.genreArray[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//To get the Genre
selectedGenre = model.data[indexPath.row][1]
for indexPath in model.data{
if indexPath[1] == selectedGenre{
selectedGenre.append(indexPath[0])
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "pushToMovies") {
if let VC = segue.destination as? FilteredSelection {
VC.selectedMovies = [selectedGenre]
}
}
}
func didRecieveDataUpdate(data: [[String]]) {
//=================here you need to update your tableView===================
}
deinit{
}
}

showing an error as has need to conform the protocol

This is my code:-
Model:-
class QuestionListModel: NSObject {
var optionsModelArray:[OptionsModel] = []
var question:String!
init(dictionary :JSONDictionary) {
guard let question = dictionary["question"] as? String
else {
return
}
if let options = dictionary["options"] as? [String]{
print(options)
print(options)
for values in options{
print(values)
let optionmodel = NH_OptionsModel(values: values)
self.optionsModelArray.append(optionmodel)
}
}
self.question = question
// print(self.dataListArray33)
}
}
optionModel:-
class OptionsModel: NSObject {
var values:String?
init(values:String) {
self.values = values
print( self.values)
}
}
in viewmodel:-
var questionsModelArray:Array<NH_QuestionListModel>? = []
init(withdatasource newDatasourceModel:NH_QuestionDataSourceModel) {
datasourceModel = newDatasourceModel
print(datasourceModel.dataListArray?.count)
self.questionsModelArray = datasourceModel.dataListArray
print(self.questionsModelArray)
print(datasourceModel.dataListArray)
}
func numberOfSections() -> Int{
return (self.questionsModelArray?.count)!
}
func titleForHeaderInSection(atindexPath indexPath: IndexPath) -> QuestionListModel {
return self.questionsModelArray![indexPath.row]
}
func numberOfRowsInSection(indexPath:IndexPath) -> Int {
if let questionModel = self.questionsModelArray?[indexPath.section]{
return questionModel.optionsModelArray.count
}
else{
return 0
}
}
func datafordisplay(atindex indexPath: IndexPath) -> OptionsModel{
let questionModel = self.questionsModelArray?[indexPath.section]
return questionModel!.optionsModelArray[indexPath.row]
}
And in ViewController:-
func numberOfSections(in tableView: UITableView) -> Int {
return questionViewModel.numberOfSections()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: IndexPath) -> UIView? {
// let headercell = Bundle.main.loadNibNamed("HeaderCell", owner: self, options: nil)?.first as! NH_questionheader
let identifier = "HeaderCell"
var headercell: NH_questionheader! = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
if headercell == nil {
tableView.register(UINib(nibName: "NH_questionheader", bundle: nil), forCellReuseIdentifier: identifier)
headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
}
headercell.setReviewData(reviews:questionViewModel.titleForHeaderInSection(atindexPath:section))
return headercell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: IndexPath) -> Int {
return questionViewModel.numberOfRowsInSection(indexPath: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
var cell: CellTableViewCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? CellTableViewCell
if cell == nil {
tableView.register(UINib(nibName: "CellTableViewCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? CellTableViewCell
}
cell.contentView.backgroundColor = UIColor.clear
cell.setOptions(Options1: questionViewModel.datafordisplay(atindex: indexPath))
print("Section \(indexPath.section), Row : \(indexPath.row)")
return cell
}
my json file:-
{
"data":[
{
"question": "Gender",
"options": ["Male","Female"]
},
{
"question": "How old are you",
"options": ["Under 18","Age 18 to 24","Age 25 to 40","Age 41 to 60","Above 60"]
}, {
"question": "I am filling the Questionnaire for?",
"options": ["Myself","Mychild","Partner","Others"]
}
]
}
This is my data .So i need to display the questions in header and options in the cell for index .But showing as error as UITableview has need to conform the protocol UITableviewDataSource.
Also showing error as Index out of range.
How to do.....
I think you are not assign a datasource to your view controller. So please assign it in your ViewDidLoad of your view controller
override func viewDidLoad() {
super.viewDidLoad()
self.yourtableview.delegate = self
self.yourtableview.dataSource = self
// Do any additional setup after loading the view.
}
This error usually occurs when you fail to implement the required methods of a protocol. In this case the methods would be :
cellForRowAt
numberOfRowsInSection
Since you already have them implemented in your view controller chances are that you might have failed to set the datasource for the table view.
Refer to this
https://developer.apple.com/documentation/uikit/uitableviewdatasource
your view controller cannot find the data source and delegate for the table view. make sure you have assigned the data source and delegate
self.yourtableview.delegate = self
self.yourtableview.dataSource = self
and also make sure that your controller also inherit the UITableViewDelegate and UITableViewDataSource like this
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
To achieve what you want, you should set your VC as the delegate and datasource of your table.
Option 1, do it dynamically:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
Option 2, from your storyboard (example below):
After this, you should use the following datasource functions of UITableView:
// return number of questions
func numberOfSections(in tableView: UITableView) -> Int
// return number of options per question (indicated by section)
func tableView(UITableView, numberOfRowsInSection: Int) -> Int
You haven't correctly declared the numberOfRowsInSection function; section is an Int, not an IndexPath. As a result you have not implemented the mandatory functions of UITableViewDataSource.
You want:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionViewModel.numberOfRowsIn(section: section)
}
With an appropriate change in your view model:
func numberOfRowsIn(section:Int) -> Int {
return self.questionsModelArray?[section].optionsModelArray.count ?? 0
}
I would also suggest that you review your use of implicitly unwrapped optionals and force unwrapping; this is just asking for crashes.
For example, there is no reason for the question property of QuestionListModel to be String!; just declare it as String and make your initialiser failable. Better yet, use Codable to create your model from JSON and get rid of all of that code.
You can eliminate the force unwrapping in numberOfSections too:
func numberOfSections() -> Int {
return self.questionsModelArray?.count ?? 0
}
I would also suggest you make QuestionListModel a struct rather than an NSObject subclass.
If I were you I would re-factor to remove the view model, it is adding unnecessary complexity in this case, and use Codable for your JSON deserialisation:
struct Questions: Codable {
enum CodingKeys: String, CodingKey {
case questions = "data"
}
var questions: [Question]
}
struct Question: Codable {
var question: String
var options: [String]
}
Your view controller then becomes much simpler:
class ViewController: UIViewController, UITableViewDatasource {
var questionData: Questions?
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "NH_questionheader", bundle: nil), forCellReuseIdentifier: "HeaderCell")
tableView.register(UINib(nibName: "CellTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
// You don't show how you load your JSON, but assuming you have it in an instance of `Data` called `jsonData`:
do {
self.questionData = try JSONDecoder().decode(Questions.self, from: jsonData)
} catch {
print("Error decoding JSON: \(error.localizedDescription)")
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: IndexPath) -> UIView? {
let identifier = "HeaderCell"
guard let questionData = self.questionData,
let headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader else {
return nil
}
headercell.label.text = questionData.questions[section].question
return headercell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.questionData?.questions[section].options.count ?? 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.questionData?.questions.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Cell"
// Note, I have used force unwrapping and a forced downcast here as if either of these lines fail you have a serious problem and crashing is the simplest way of finding it during development
let option = self.questionData!.questions[indexPath.section].options[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath ) as! CellTableViewCell
cell.contentView.backgroundColor = .clear
cell.label.text = option
return cell
}
}
Once you have this basic approach working you can try and add a view model if you like.

Convert JSON to a Array with struct

I am trying to make a IOS app that is a home automation thing. I am using TableViewCell to display information.
My problem is that I have no idea how to get JSON to an Array with struct because I have to have struct I think.
My JSON is:
[{"namea":"TV","statea":"up_tv"},{"namea":"test","statea":"test"}]
My code is:
struct cellData {
let nameLabel : String!
let stateLabel : String!
}
class Main: UITableViewController {
var array = [cellData]()
override func viewDidLoad() {
array = [cellData(nameLabel: "tv", stateLabel: "up_tv"),
cellData(nameLabel: "tv", stateLabel: "down_tv")]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("TableViewCell", owner: self, options: nil)?.first as! TableViewCell
cell.nameLabel.text = array[indexPath.row].nameLabel
cell.stateLabal.text = array[indexPath.row].stateLabel
return cell
}
You need jsonDecoder
struct cellData : Decodable {
let nameLabel : String
let stateLabel : String
enum CodingKeys:String,CodingKey {
case nameLabel = "namea"
case stateLabel = "statea"
}
}
//
let str = """
[{"namea":"TV","statea":"up_tv"},{"namea":"test","statea":"test"}]
"""
do {
let cellArr = try JSONDecoder().decode([cellData].self, from: str.data(using:.utf8)!)
print(cellArr) //// check this
} catch {
}
//
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "id") as TableViewCell
}

Infinite scroll with UITableView and an Array

I'm new in Swift and I want to make an infinite scroll with an Array. Here it's my class TableViewController
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var legumes: [String] = ["Eggs", "Milk", "Chocolat", "Web", "Miel", "Pop", "Eco", "Moutarde", "Mayo", "Thea", "Pomelade", "Gear", "Etc" , "Nop", "Dews", "Tout", "Fun", "Xen" , "Yoga" ]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.legumes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ImageTableViewCell
return cell
}
}
I want to show the first ten items of my array and when I am on the bottom of the TableViewController, it will load the next ten items, etc. I don't know how to do, I see a lot of code on GitHub but I don't know how to implement them.
Thank you so much.
Consider using PagingTableView
class MainViewController: UIViewController {
#IBOutlet weak var contentTable: PagingTableView!
var legumes: [String] = ["Eggs", "Milk", "Chocolat", "Web", "Miel", "Pop", "Eco", "Moutarde", "Mayo", "Thea", "Pomelade", "Gear", "Etc" , "Nop", "Dews", "Tout", "Fun", "Xen" , "Yoga" ]
override func viewDidLoad() {
super.viewDidLoad()
contentTable.dataSource = self
contentTable.pagingDelegate = self
}
}
extension MainViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return legumes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ImageTableViewCell
guard legumes.indices.contains(indexPath.row) else { return cell }
cell.content = legumes[indexPath.row]
return cell
}
}
extension MainViewController: PagingTableViewDelegate {
func paginate(_ tableView: PagingTableView, to page: Int) {
contentTable.isLoading = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.legumes.append(contentsOf: legumes)
self.contentTable.isLoading = false
}
}
}
Modify the paginate function to work as you wish
What you're describing is called pagination. You should do something like this:
/* Number of page you're loading contents from */
var pageIndex: Int = 1
override func scrollViewDidScroll(scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
if offsetY > contentHeight - scrollView.frame.size.height {
/* increment page index to load new data set from */
pageIndex += 1
/* call API to load data from next page or just add dummy data to your datasource */
/* Needs to be implemented */
loadNewItemsFrom(pageIndex)
/* reload tableview with new data */
tableView.reloadData()
}
}

Resources