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()
Related
I have a tableview , it has two rows.
Tableview's height is 700. The first row height is 150 and the second row height is 100 but I'd like the second cell to cover the rest of the space in tableview.
I know I can use the below for tableview height. But I'd like to
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
Simply, just replace this method
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let tblHeight = infoTable.bounds.size.height
return indexPath.row == 0 ? 150 : tblHeight - 150
}
just change infoTable with your table name.
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.
Hello,
i have created a UITableView in which it has two different cells DynamicFormCell and StaticFormCell, so the DynamicFormCell can be displayed number of times i have a data from a server telling me how many forms i need for the DynamicFormCell and the StaticFormCell is always the same and doesn't change so i am having difficulty giving different number of rows for each cell.i tried giving the two cell a tag of 0 and 1 respectively and used this code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(tableView.tag == 0){
return 5//return five dynamic cells
}
if(tableView.tag == 1){
return 1//return one static cell
}
}
but this doesn't work and i also tried removing all the tags and if statements in the above code and just doing this return 5 this just gave me one DynamicFormCell and five StaticFormCells.
i also gave different classes for the two cells so i can assign them separately:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row == 0){
//firstRow make dynamic
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicFormsCell") as! DynamicFormsCell
return cell
}else{
//static form data
let cell = tableView.dequeueReusableCell(withIdentifier: "StaticFormsCell") as! StaticFormsCell
return cell
}
}
so my question is, is it possible to do this using table views and how can i do it? if not what other options do i have?
Yes it is possible to have multiple types of cell in single tableview. It has nothing to do with function
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
You should return there cells as,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (count of dynamic cells + count of static cells)
}
I assume, you only have to display static cells in the bottom. So if there are total 5 cells then 4 cells are dynamic and 5th cell would be static.
So code for, cellForRowAt indexPath: will be,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row < (count for dynamic cells)){
//first 4 Rows make dynamic
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicFormsCell") as! DynamicFormsCell
return cell
}else{
//last row static form data
let cell = tableView.dequeueReusableCell(withIdentifier: "StaticFormsCell") as! StaticFormsCell
return cell
}
}
What you're doing right now is checking if the TableView's tag is 0 or 1. Which is not you want to do, since you're using only one TableView.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (amount of DynamicCellsYouWant + amount of StaticCellsYouWant)
}
The second part of your code only works when you want the first cell to be a DynamicFormsCell and the rest to be a StaticFormsCell.
I am trying to add some rows in my table view. when inserting rows are above the rows which are on the screen, the table view jumps up. I want my table view to stay in the position it is already in when I insert rows above. Keep in mind: tableView jump to indexPath that it was showing but after adding rows above, bottom rows indexPaths changes and the new n'th indexPath is something else.
This is unfortunately not as easy task as one would think. Table view jumps when you add a cell on top because the offset is persisted and cells updated. So in a sense it is not the table view that jumps, cells jump since you added a new one on top which makes sense. What you want to do is for your table view to jump with the added cell.
I hope you have fixed or computed row heights because with automatic dimensions things can complicate quite a bit. It is important to have the same estimated height as actual height for row. In my case I just used:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 72.0
}
Then for testing purposes I add a new cell on top whenever any of the cells is pressed:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var offset = tableView.contentOffset.y
cellCount += 1
tableView.reloadData()
let paths = [IndexPath(row: 0, section: 0)]
paths.forEach { path in
offset += self.tableView(tableView, heightForRowAt: path)
}
DispatchQueue.main.async {
tableView.setContentOffset(CGPoint(x: 0.0, y: offset), animated: false)
}
}
So I save what the current offset of the table view is. Then I modify the data source (My data source is just showing number of cells). Then simply reload the table view.
I grab all the index paths that have been added and I modify the offset by adding the expected height of every added cell.
At the end I apply the new content offset. And it is important to do that in the next run loop which is easies done by dispatching it asynchronously on main queue.
As for automatic dimensions.
I would not go there but it should be important to have size cache.
private var sizeCache: [IndexPath: CGFloat] = [IndexPath: CGFloat]()
Then you need to fill the size cache when cell disappears:
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
sizeCache[indexPath] = cell.frame.size.height
}
And change the estimated height:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return sizeCache[indexPath] ?? 50.0
}
Also when modifying your offset you need to use estimated height:
paths.forEach { path in
offset += self.tableView(tableView, estimatedHeightForRowAt: path)
}
This worked for my case but automatic dimensions are sometimes tricky so good luck with them.
I have a table view which reloads it data with animation on button tap. It was working great until there was one label with text.
I use this code to reload data with animation for one button (I have only one section):
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.right)
and this for another button:
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.left)
And on the top of table view it works okay, but in the middle or in the end it scrolling.
Link for gif - https://giphy.com/gifs/l0DAHUyzm7BMGnKrm/html5
Then I added this code for reloading with animation:
let offset = tableView.contentOffset
tableView.beginUpdates()
tableView.reloadSections(IndexSet(integersIn: 0..<tableView.numberOfSections), with: UITableViewRowAnimation.left)
tableView.endUpdates()
tableView.layer.removeAllAnimations()
tableView.setContentOffset(offset, animated: false)
Same code for .right animation. It fixed scrolling, but added another issue. Again on top of table view it works okay, but then... Watch gif please.
Link for gif - https://giphy.com/gifs/xT1R9Gfaa2po6dMf2U/html5
I'm using test data to fill table view, not fetching or something else.
Hope for help, thanks
EDIT:
I found that if I set standard cell height from code animation works nice, only in this case it works:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 44.0
}
I found the problem. The problem was in cell height, animation was starting for estimated cell height in 44.0 and my cell height is 117.0. So this code fixed my problem:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 117.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 117.0
}