UITableView incorrect offset after .reloadSections - ios

I have next code when I tap to show / hide content.
func showHideAssets() {
isOpenHiddenAssets = !isOpenHiddenAssets
tableView.beginUpdates()
tableView.reloadSections(IndexSet(integer: 1), with: .fade)
tableView.endUpdates()
}
When first section contain many items, after reloading sections table scrolling to bottom with incorrect offset
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 10
}
return isOpenHiddenAssets ? assetsHiddenItems.count : 0
}
Video where first section have 3 items. It works well
video 1
Video where first section have 10 items. It have bug.video 2

The solution is replacing
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
with
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat

Related

Error after cell insertion: invlalid number of sections

After receiving a new object, I call this func to insert a cell:
private func addCellToTheTop(recipe: Recipe) {
guard let recipeTableView = self.recipeTableView else { return }
recipesForShow.insert(recipe, at: 0)
recipeTableView.beginUpdates()
recipeTableView.insertRows(at: [IndexPath.init(row: 0, section: 0)], with: .automatic)
recipeTableView.endUpdates()
}
But I get an error
Why the number of section does not match?
If it is important:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return recipesForShow.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return TableCellConfig.spaceBetweenCells
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clear
return headerView
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//...
}
You are getting this exception because you are appending a new element to the array that is being used to determine the numberOfSection whereas you are inserting a new row into the tableView. To fix this you need to insert section instead of inserting new row, here's how:
recipeTableView.insertSections([0], with: .automatic)

Different cell depending on the cell text

I have the following situation. I am making a weather app and I am displaying the data in cells for a period of days. I have the following structure:
Day1
Min temperature
Max temperature
Day2
Min temperature
Max temperature
Day3
Min temperature
Max temperature
etc etc...
I am also using sections and the following functions:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "minimumTemperature")
cell?.textLabel?.text = "fooMinTemperature"
return cell!
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return // logic for getting the heading of the section
}
The problem comes that the override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
function can only return 1 cell at a time. So for example this function will get called two times now and add the minimum temperature two times. How can I add both the min and max temperatures.
Assuming you have some array of data where each element in the array represents one day, you would use the section to pick the data for the correct day. Then you use the row to choose between min or max temperature.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "minimumTemperature") as! UITableViewCell
let data = myArrayOfDays[indexPath.section]
let temp = indexPath.row == 0 ? data.minimumTemp : data.maximumTemp
cell.textLabel?.text = "\(temp)"
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func numberOfSections(in tableView: UITableView) -> Int {
return myArrayOfDays.count
}
The variable names I used are clearly just examples. Update with your own as needed.
Your section header can show the day number.

Scroll not working in table view with dynamic cell height

I am building a chat application using UITableView in Swift 4 programatically . This table view have dynamic cell height. So when I am insert a new row to table view and call
self.m_ChatTable.scrollToRow(at: lastIndex, at: .top, animated: true)
not working properly. For example when I am inserting two new rows to table view the 1st row become visible after inserting the 2nd row and 2nd row become visible after inserting 3rd row . The scrolling height in tableView not correct.
Code
override func viewDidLoad() {
super.viewDidLoad()
m_ChatTable.rowHeight = UITableViewAutomaticDimension
m_ChatTable.separatorStyle = .none
m_ChatTable.delegate = self
m_ChatTable.dataSource = self
m_MainScrollView.addSubview(m_ChatTable)
m_ChatTable.reloadData()
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let msg:Message = m_MessageList[indexPath.row] as Message
return msg.height + 10
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
return 50 // for example
}
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let msg = m_MessageList[indexPath.row]
if (0 != msg.height)
{
return msg.height + 10
}
else
{
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let height = cell.frame.height
m_MessageList[indexPath.row].height = height
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.m_MessageList.count
}

UITableView Section Index Out Of Bounds but it's not really out of bounds

Whenever I run the app, the tableView has no data, waiting for user to input. The problem is that if the numberOfSections is 1, it works just fine, but when I change it to 2 it crashes because Index out of range
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "expenseCell") as? ExpenseCell else { return UITableViewCell() }
let budget = userBudget[indexPath.section][indexPath.row]
cell.delegate = self
cell.configureCell(budget: budget)
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.none
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userBudget[section].count // <- Crash here
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Practice with Sections \(section)"
}
It is because you are accessing index 1 of userBudget while i assume it contains 0 index only.
This crash happens cause your array userBudget, don't has two elements at the moment you try access his second position.
You must guard that userBudget has two elements on minimium...
You should that you must to assign value to userBudget on your ViewDidLoad.
You are saying that you will have two section to your tableView's delegate, but you have an array which contains only one array. Basically when you try to reach userBadget[1] in your numberOfRowsInSection function and it crashes because it doesn't exist.
Replace
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
With
func numberOfSections(in tableView: UITableView) -> Int {
return userBudget.count
}

Strange issue with displaying cells in UITableView

I have UITableView with methods:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
override func numberOfSections(in tableView: UITableView) -> Int
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
So, the problem is that Xcode runs at first
override func numberOfSections(in tableView: UITableView) -> Int
which returns me 1.
Later it runs override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int which also returns me 1.
BUT I do not know why after these 2 methods it does not run cellForRowAt method and does not display any row on my UITableView.
I do not know what happens there and why this happens.
Have you met such problem and could you please help me to fix it?
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let fetchedResultsController = self.fetchedResultsController, let fetchedObjects = fetchedResultsController.fetchedObjects {
if !searchController.isActive {
print("numberOfRowsInSection fetchedObjects.count - \(fetchedObjects.count)")
return fetchedObjects.count
} else {
if let results = filteredResult[searchController.searchBar.selectedScopeButtonIndex] {
print("numberOfRowsInSection results.count - \(results.count)")
return results.count
}
}
}
print("numberOfRowsInSection - 0")
return 0
}
override func numberOfSections(in tableView: UITableView) -> Int {
if let frc = fetchedResultsController, frc.fetchedObjects?.count != 0 {
print("numberOfSections - 1")
return 1
} else {
print("numberOfSections - 0")
return 0
}
}
What is probably happening is that your cell has height 0. When this happens, cellForRowAt won't be called at all, even if the other methods return a non zero section/row count.
My guess as to why this is happening is that you may be using auto layout for your cell, but your constraints don't allow the cell to figure out its own height. You may be using auto layout unknowingly, since on iOS 11, it's now the default. If you are using storyboards you can set the height for the cell prototype on the attributes inspector, instead of checking the automatic box. Alternatively, you can set it in code with tableView.rowHeight or by implementing func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat

Resources