I'm trying to insert number more cells in the table view when the user reaches the bottom of the table. the insert is working fine, but a weird animation is happening when scrolling up.
I tried to add beginUpdates()
and endUpdates()
before and after the insert()
method. but this didn't help. I tried to add tableView.contentInsetAdjustmentBehavior = .never
in viewDidLoad
and it didn't help.
the code I tried is:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if tableView.contentOffset.y >= (tableView.contentSize.height - tableView.frame.size.height) {
loadMoreCells()
}
func loadMoreCells() {
ServerRequests.getDataServerRequest(id: provider.ID, page: page) { (foundEpisodes) in
if foundEpisodes.count > 0 {
let previous = self.episodes.count
self.episodes.insert(contentsOf: foundEpisodes, at: self.episodes.count)
self.isViewOpen.insert(contentsOf: [Bool](repeatElement(false, count: foundEpisodes.count)), at: self.isViewOpen.count)
var indexPathsToBeInserted = [IndexPath]()
for i in previous..<self.episodes.count{
indexPathsToBeInserted.append(IndexPath(row: i, section: 0))
}
self.tableView.insertRows(at: indexPathsToBeInserted, with: UITableViewRowAnimation.none)
}
}
}
Am I calling the insert in the wrong place? or what is the wrong thing I am doing ?
UPDATE
in viewDidLoad
:
tableView.register(UINib(nibName: NIB_NAME, bundle: nil), forCellReuseIdentifier: NIB_IDENTIFIRE)
in cellForRow
:
let cell = tableView.dequeueReusableCell(withIdentifier: NIB_IDENTIFIRE, for: indexPath) as! EpisodePerProviderTableViewCell
cell.setUpCell(tableView: tableView, episode: episodes[indexPath.row], indexPath: indexPath, isViewOpen: isViewOpen)
return cell
the setUpCell
function is:
unc setUpCell(tableView: UITableView, episode: Episode, indexPath: IndexPath, isViewOpen: [Bool]) {
isMenuVisible = false
menuView.isHidden = true
if (isViewOpen[indexPath.row]){
descriptionLabel.numberOfLines = 100
moreLessLabel.text = "Less"
}else{
descriptionLabel.numberOfLines = 2
moreLessLabel.text = "More"
}
tableView.beginUpdates()
tableView.endUpdates()
self.isViewOpen = isViewOpen
self.indexPath = indexPath
self.tableView = tableView
self.episode = episode
arrowButton.transform = .identity
//set up cell content
if let myDate = dateFormatter.date(from: episode.episodePostDate) {
postedDate.text = dateFormatter.timeSince(from: myDate as NSDate)
}
episodeImage.windless.start()
episodeImage.sd_setImage(with: URL(string: episode.episodeImageUrl ?? ""), placeholderImage: UIImage(named: "FalloundPlayerLogo")) { (providerImage, error, SDImageCacheType, url) in
self.episodeImage.windless.end()
}
title.text = episode.episodeName
durationLabel.text = "".formatted(time: Float(episode.episodeDuration), withoutSec: true)
descriptionLabel.text = episode.episodeDescription
}
I think the problem is because loadMoreCells is called too many times.
try using this check instead of willDisplay:
if indexPath.row == yourArrayOfCells.count - 1{
loadMoreCells()
}
UPDATE
So I have some how of the same issue, after some digging I found this solution for myself :
//conform to UIScrollViewDelegate
let threshold : CGFloat = 10.0 // threshold from bottom of tableView
var isLoadingMore = false //checks if API session ended
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if !isLoadingMore && (maximumOffset - contentOffset) <= threshold {
self.isLoadingMore = true
DispatchQueue.main.async {
loadMoreCells()
self.isLoadingMore = false
}
}
}
If the API request happening too fast and the load looks funny you can add a delay :
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
loadMoreCells()
self.isLoadingMore = false
}
If it won't work I will assume that the issue is not in the code you provided.
UPDATE-2
Those 2 funcs in setUpCell() aren't neccessery :
tableView.beginUpdates()
tableView.endUpdates()