I've a table view where cells can be inserted and deleted. For insertion of cells, I use the following code:
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: cellCount-2, section: 0)], with: .automatic)
tableView.endUpdates()
For deleting cells, I use the following code:
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
Attaching the gif of the issue I face. On deleting a cell and inserting a new one, the contents of the cell gets populated in the new cell. Can someone help me sort this issue?
If you are using the standard UITableViewCell remember to reset the content inside the UITableViewDelegate function cellForRowAtIndexPath since the dequeueReusableCell will recycle an already initialized cell (that has to be brought to its original state)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "aCellIdentifier", for: indexPath)!
...
cell.title.text = ""
cell.description.text = ""
}
A typical approach is however to subclass UITableViewCell and implement prepareForReuse method (which is called automatically before the cell being reused), where you will eventually reset all labels, images, subviews to the initial state
override func prepareForReuse() {
super.prepareForReuse()
self.labelScore.text = ""
self.labelDate.text = ""
}
Related
I am trying to delete row from UITableView by using trailingSwipeActionsConfigurationForRowAt function.
The row gets deleted and disappears. This part is ok.
But next rows that are coming to the screen or when I swipe down the same amount as the rows been deleted are not even loaded on the tableView.
![img1]https://poirot.deus4.com/photo_2019-06-12_16-44-01.jpg
![img2]https://poirot.deus4.com/photo_2019-06-12_16-43-56.jpg
![img3]https://poirot.deus4.com/photo_2019-06-12_16-43-49.jpg
![img4]https://poirot.deus4.com/photo_2019-06-12_16-43-38.jpg
[video]https://poirot.deus4.com/RPReplay_Final1560345600.mp4
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredProducts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: .cellID, for: indexPath) as! ProductTableCell
cell.backgroundColor = .red
return cell
}
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let hide = UIContextualAction(style: .destructive, title: "Hide") { action, view, completion in
self.filteredProducts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
completion(true)
}
hide.image = #imageLiteral(resourceName: "hdie_product")
hide.backgroundColor = .midGrey
let conf = UISwipeActionsConfiguration(actions: [hide])
return conf
}
The code you showed obviously works, thus the problem is elsewhere.
Without other code I suspect that the problem is because table view cells are re-used: When you scroll your table view, some cells are scrolled out of view and can be reused. Cells that are scrolled in are either re-used cells or new cells.
In any case, the table view datasource function tableView(_:cellForRowAt:) must be used to configure the displayed cells.
It seems too me that you do not configure the cells in tableView(_:cellForRowAt:).
If so, re-used cells look as the were when they have been scrolled out, but new cells are simply blank.
So I suggest to check if you really configure all the cells in tableView(_:cellForRowAt:) correctly.
The issue was that I did not call super.prepareForReuse() inside TablewViewCell
override func prepareForReuse() {
super.prepareForReuse() // this was missing
}
I need to update tableview cell without reloadRows and reloadData method in swift. Is It possible?
You can use tableview.indexPathsForVisibleRows if you wanna just update the ones on the screen and the others will be updated through cellForRow / willDisplayCell
Then you would traditionally do something like
tableview.indexPathsForVisibleRows.forEach {
if let cell = tableview.cellForRow(at: $0) as? MyCell {
cell.configure()
}
}
Try this piece of code:
UIView.setAnimationsEnabled(false)
self.yourTableView.beginUpdates()
self.yourTableView.reloadSections(NSIndexSet(index:indexToBeReload) as IndexSet, with: UITableViewRowAnimation.none)
self.yourTableView.endUpdates()
If You want to update cell content size, You should use beginUpdates() and endUpdates() to change content size of UITableViewCell, in this case heightForRowAtindexPath will called for each cell in tableView and update height of TableviewCell. for iOS > 10, You should prefer performBatchUpdates(_:completion:) instead of beginUpdates() and endUpdates().
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
For more information
https://appengineer.in/2018/07/11/resize-uitableviewcell-size-without-fluctuation-and-jerk/
https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates
I am having this weird issue. when I scroll tableview and update some cell it bounce equivalent to the amount first cell scrolled.
I am having one view controller with tableview in it and based on user select some rows i'm updating only that row using below code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let index = indexPath.row
print(index)
let service = services[indexPath.row]
if service.isEnabled {
service.isEnabled = false
}
else {
service.isEnabled = true
}
let indexPath = IndexPath(item: index, section: 0)
serviceTableView.reloadRows(at: [indexPath], with: .fade)
}
this is working fine if I don't scroll the table view but if i scroll table view and select some cell its bounce the entire tableview
Things already tried
Removing all constraints of table view, it still bounce
Removing all config methods from cellForRowAt indexPath
Different simulators
also I am not doing anything in section view.
PS: What I observe is that it only happens when first cell is partially visible/hidden.
Is there any way that I could reload only tableViewCell only but don't make it reload tableView section title View ? when I switched UITableViewCell I want to update data reload change
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch self[selectedIndex] {
case .tracks:
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! TracksCell
return cell
case .playlists:
let cell = tableView.dequeueReusableCell(withIdentifier: cellPlayListId, for: indexPath) as! PlaylistCell
return cell
}
What I want to do is just reload UITableViewCell only I don't want to reload this code below
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {}
if I use tableView.reload() it will effected my style in viewForHeaderInSection Because I have added UIViewScroll
thank you for your help!
If you want to reload only particular tableView cell then use this:
tableView.reloadRows(at: [IndexPath(row: rowNumber, section: 0)], with: .automatic)
It reload only cell not the section.
Reload the Particular UITableViewCell
tableviewCart.reloadRows(at: [indexPath!], with: .none)
Look for the table view delegate methods for reloading views. These are:
open func reloadSections(_ sections: IndexSet, with animation: UITableView.RowAnimation)
open func reloadRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation)
open func reloadData()
Here in your case, reloadRows will be the best suitable option, as:
tableView.reloadRows(at: <[IndexPath]>, with: .automatic)
Where, <[IndexPath]> is the array of index path of the cells. For example:
let cell0FromSection0 = IndexPath(row: 0, section: 0)
let cell2FromSection0 = IndexPath(row: 2, section: 0)
let cell1FromSection1 = IndexPath(row: 1, section: 1)
tableView.reloadRows(at: [cell0FromSection0, cell2FromSection0, cell1FromSection1], with: .automatic)
You can reload particular cell in UITableView with below code.
let cellNmber = IndexPath(row: rowNumber, section: sectionNummber)
tableView.reloadRows(at: [cellNmber], with: .automatic)
or
tableView.reloadRows(at: [cellNmber], with: .none)
If you want to reload cell with default animation then go with .automatic.
If you want to reload cell without animation then go with .none.
You can also reload multiple cell in a tableView by providing IndexPath array.
e.g.
tableView.reloadRows(at: [cellNmber1,cellNmber3,cellNmber5], with: .automatic)
I have an UITableView with custom cells. Cells can be expanded when tapped.
I calculate the height with the delegate heightForRowAtIndexPath
The animation coming with reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None) looks really nice but doesn't work if a part of the bigger expanded cell is out of the screen. Then it just kind of pops (it looks like a jump), no nice "sliding"- animation (sorry i don't know the right animation-phrases), like when the cell is completely visible on the screen.
I already tried out reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) that made that nice sliding even if the expanded cell is out of the screen border but the upper part of my cell is just getting brighter for a moment and that doesn't look very fancy..
So anyone having trouble with that "animation" .None, too? ^^"
My did-select-func:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? ProviderNewTableViewCell {
if expandedCells.contains(indexPath) {
expandedCells.removeObject(indexPath)
}
else {
expandedCells.append(indexPath)
}
//This prevents the last cell glitching into the decreasing cell above
CATransaction.begin()
CATransaction.setCompletionBlock({ () -> Void in
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
})
CATransaction.commit()
}
}
My cell-for-row-func (the important parts ;) )
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("ProviderNewCell", forIndexPath: indexPath) as! ProviderNewTableViewCell
if expandedCells.contains(indexPath) {
indexPathDetailViewDict[indexPath] = ProviderCellBuilder.sharedInstance.buildDetailView(cell, prov: current)
}
}