I have been setting the cell heights for my tableview with
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 0:
return 100
case 1:
tableView.estimatedRowHeight = 100
return UITableViewAutomaticDimension
default:
return 0
}
}
With this, for all the rows in section 1, the rowheight is set to 100. Now, I would like to change the row height of a particular row to set to 0 (i.e. make it hidden) on button click.
I have tried:
tableView.cellForRow(at: IndexPath(item: selectedIndex, section: 1))?.isHidden
Although the cell is hidden, I am left with a blank cell occupying the row height.
So I think I should be changing the row height to 0.
P.S. I know this can be achieved by removing the particular row from the model and using deleteRows(at indexPaths: [IndexPath],
with animation: UITableView.RowAnimation) But I do not want to change the model. How can this be done?
Use a flag to check if you clicked the button. Then reload the table after button click.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.section == 0 ? buttonClicked && indexPath.row == 0 ? CGFloat.leastNormalMagnitude : 100 : UITableViewAutomaticDimension
}
Longer, more readable version :-
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 0:
if buttonClicked && indexPath.row = rowIndex //index of required row which you can find out and store in a variable wherever necessary {
return CGFloat.leastNormalMagnitude
}
return 100
case 1:
tableView.estimatedRowHeight = 100
return UITableViewAutomaticDimension
default:
return 0
}
}
Related
I have a tableview. I created it from storyboard it is a static tableview.(I am using it for profile settings).
But i have to change height of the first row of this table view dynamically and i don't want to change other cell heights. They should use their storyboard height values. How can i do this?
I tried following code:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
}
return (tableView.cellForRow(at: indexPath)?.bounds.height)!
}
But this is setting 100 for all cells.
My tableview:
Use the following override function..
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
}
return UITableView.automaticDimension
}
But you have to make sure that every item in the static tableview have (top/bottom/left/right) constraints. it only works when it have all these constraints on it.
So every time I scroll my tableView it reloads data which I find ridiculous since it makes no sense to reload data as it hasn't been changed.
So I setup my tableView as follows:
func numberOfSections(in tableView: UITableView) -> Int {
return self.numberOfElements
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 6
}
My cells are really custom and they require spacing between them. I couldn't add an extra View to my cell to fake that spacing because I have corner radius and it just ruins it. So I had to make each row = a section and set the spacing as a section height.
My cell has a dynamic height and can change it's height when I click "more" button, so the cell extends a little.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if self.segmentedControl.selectedSegmentIndex == 0 {
if self.isCellSelectedAt[indexPath.section] {
return self.fullCellHeight
} else {
return self.shortCellHeight
}
} else {
return 148
}
}
And here's how I setup my cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if self.segmentedControl.selectedSegmentIndex == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: String.className(CurrentDocCell.self)) as! CurrentDocCell
(cell as! CurrentDocCell).delegate = self
(cell as! CurrentDocCell).ID = indexPath.section
} else {
cell = tableView.dequeueReusableCell(withIdentifier: String.className(PromissoryDocCell.self)) as! PromissoryDocCell
}
return cell
}
So I have a segmentedControl by switching which I can present either one cell of a certain height or the other one which is expandable.
In my viewDidLoad I have only these settings for tableView:
self.tableView.registerCellNib(CurrentDocCell.self)
self.tableView.registerCellNib(PromissoryDocCell.self)
And to expand the cell I have this delegate method:
func showDetails(at ID: Int) {
self.tableView.beginUpdates()
self.isCellSelectedAt[ID] = !self.isCellSelectedAt[ID]
self.tableView.endUpdates()
}
I set a breakpoint at cellForRowAt tableView method and it indeed gets called every time I scroll my tableView.
Any ideas? I feel like doing another approach to make cell spacing might fix this issue.
A UITableView only loads that part of its datasource which gets currently displayed. This dramatically increases the performance of the tableview, especially if the datasource contains thousands of records.
So it is the normal behaviour to reload the needed parts of the datasource when you scroll.
I'm building an app which presents departures of busses. I use a tableview to represent it, the name of the busstop is set as the section header, and each row in a section represents a departure from that busstop.
The API always provide me with the next 20 departures for each stop, but initially I just show the next 6 departures in each section, I keep all the 20 in my datasource though. At the end of each section I have a cells which is supposed to double the shown departures in each section. It's done it this way:
tableView.beginUpdates()
tableView.reloadSections(NSIndexSet(index: indexPath.section) as IndexSet, with: .none)
tableView.endUpdates()
My initial thought was that I could just double the returnvalue of the numberOfRowsInSection-function for the specific section, but that doesn't seem to work.
var scale = [Int : Int]()
func numberOfSections(in tableView: UITableView) -> Int {
if stops.count != nil {
return stops.count
} else {
return 1
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stops[indexPath.row].departures.count - scale[stops[section].id]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if stops != nil {
let currentDeparture = stops[(indexPath as NSIndexPath).section].departures![(indexPath as NSIndexPath).row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DepartureTableViewCell
// Configuration of the cell
return cell
}
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == (stops[indexPath.row].departures.count)! {
var currentScale = scale[stops[indexPath.section].id]
scale[stops[indexPath.section].id] = currentScale - 6
tableView.beginUpdates()
tableView.reloadSections(NSIndexSet(index: indexPath.section) as IndexSet, with: .none)
tableView.endUpdates()
}
}
The dictionary scale is just mapping the ID of the stop to the number of departures that should be shown, starting at 14 (20-6) and each time the cell that is supposed to reload the section is tapped, it get reduced by 6. So we get 6 more departures in the given section. currentDepartureresInSection is the number of departures at the specific stop.
It is possible to do it this way, or do I have to update the datasource of the tableview?
I have a table view with cells having dynamic height. I want to add a new row on a button click. I am incrementing the number of rows in section value and reloading the table view.But this results in a crash.I tried this after commenting the following lines
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
This is working fine when these 2 delegate methods are commented.But I want to add a new row.Dynamic height cells should be possible .How can I achieve this?
You can do like this
numberOfItems += 1
let indexPath = IndexPath(row: self.numberOfItems - 1, section: 0)
self.tbl.beginUpdates()
self.tbl.insertRows(at: [indexPath], with: .automatic)
self.tbl.endUpdates()
I have a uitableview controller with STATIC cells in two sections. I have adjusted the height of cells 0 & 1 in section 0 using storyboard. However, I have used code to expand a date picker after a UIswitch is toggled and a cell is tapped in section 1.
My problem is that the code is overriding cells 0 and 1 in section 0. How do I force those cells to take their height from storyboard? If that is not possible, how would I code their height so that the cell expansion code does not override it?
Notes: I am new and don't fully understand the code that I used to make the expansion happen, so if I need to change that, let me know. Code pasted below.
var pickerVisible = false
// MARK: - COLLAPSABLE CELL
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 && indexPath.row == 2 {
pickerVisible = !pickerVisible
tableView.reloadData()
}
tableView.deselectRow(at: indexPath, animated: true)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 1 && indexPath.row == 2 && toggle.isOn == false {
return 0.0
}
if indexPath.section == 1 && indexPath.row == 3 {
if toggle.isOn == false || pickerVisible == false {
return 0.0
}
return 165.0
}
return 44.0
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 44.0
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
// set height for rows in section 0
} else if indexPath.section == 1 {
// set height for rows in section 1
} else {
// default height for your tableview cell
return 44.0
}
}
How do I force those cells to take their height from storyboard?
-> I think you don't really need this.
How would I code their height so that the cell expansion code does not override it?
-> Its pretty easy to do what you want (sample code above)
I have found another answer that really gets to the root of what my problem was -- how to program one cell to be an exact height and have all the other cells take the height from what is put together in storyboard.
The answer is instead of returning a number in heightForRowAt, you can do the following:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 170.0
}
// OTHERWISE, RETURN WHATEVER THE TABLEVIEW WANTS.
return self.tableView.rowHeight