I have a TableViewController with rows that hold tasks. If a task has an attribute task.done = 1 I want to move it at the bottom from the table.
I can't provide any code, because I have no doubt how to do this.
My idea was in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) using following code:
let element = tasks.remove(at: indexPath.row)
tasks.insert(element, at: tasks.count)
The issue is, that this needs to be done after the table is loaded, because if the first row is done = 1 for example, it will be moved to to bottom and will be processed at the end again.
You can programmatically remove a row from UITableView and insert a row programmatically. Before doing the operations on the UITableView, make sure to remove/add a specific item to the data source array. Otherwise, it'll just crash.
If you want to simply move the rows, you can use the code below. You need to do it in the place where the array which holds the data source is updated.
tableView.moveRow(at: oldIndexPath, to: newIndexPath)
If you want to do delete and insert new objects into the array, you may try the method as shown below.
let element = tasks.remove(at: indexPath.row)
tableView.deleteRows(at: indexPath, with: .automatic)
tasks.insert(element, at: tasks.count)
tableView.insertRows(at: [IndexPath(row: tasks.count, section: 0)], with: .automatic)
Wrap your code in a beginUpdates-endUpdates block.Use func moveRow(at indexPath: IndexPath, to newIndexPath: IndexPath)
For example: Not tested
self.tableView.beginUpdates()
let element = tasks.remove(at: indexPath.row)
let movingRowIndex = indexPath.row
tasks.insert(element, at: tasks.count)
let indexPath = NSIndexPath(forRow: movingRowIndex, inSection: 0)
var lastIndexPath = NSIndexPath(forRow:tasks.count, inSection: 0)
self.tableView.moveRow(at indexPath: IndexPath, to newIndexPath: lastIndexPath)
self.tableView.endUpdates()
Related
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 = ""
}
I have a requirement where I need to show a tableview with three rows always.
When user swipes to delete a row, I need to add a new row at the bottom.
While this happens, the swipe animation which moves the row to the left to delete has to be retained. I mean delete animation should not be affected. Is this possible?
First, your dataSource must return always 3 for your numberOfRows(in:) method. Then you can commit changes this way:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableView.performBatchUpdates({
// Delete the swiped row
tableView.deleteRows(at: [indexPath], with: .left)
// Get the last row index (numberOfRows-1)
let lastRowIndex = tableView.numberOfRows(inSection: indexPath.section)-1
// Insert a new row at the end
tableView.insertRows(at: [IndexPath(row: lastRowIndex, section: 0)], with: .top)
}, completion: nil)
}
}
Don't forget to update the rest of your dataSource accordingly, because cells may be reused. The code need to be added before call performBatchUpdates. Something like that:
var cellsText = ["A","B","C"]
// Inside your tableView(:commit:forRowAt) method:
if editingStyle == .delete {
cellsText.remove(at: indexPath.row)
cellsText.append("D")
// ...
}
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.
I have installed a swipe-to-delete function in my tableview. Nothing special there. However, when performed, the red delete button (row action) overlaps while retracting to the right with the cell below even though the deleted cell has already disappeared.
In the editActionsForRowAt function I first remove the value from the array and then from a reference in Firebase. Here is the code:
func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .normal, title: "Verwijder") { action, index in
tableView.beginUpdates()
let item = self.joinedArrayFiltered[editActionsForRowAt.section][editActionsForRowAt.row]
let indexPath: IndexPath = IndexPath(row: editActionsForRowAt.row, section: editActionsForRowAt.section)
self.joinedArrayFiltered[editActionsForRowAt.section].remove(at: editActionsForRowAt.row)
self.ref.child("productsObserver").child(item.productId).child("wishlistUsers").child(self.userID).removeValue()
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.bottom)
tableView.endUpdates()
}
delete.backgroundColor = .red
return [delete]
}
To help visualize the issue, please see the attached GIF below.
Any suggestions would be helpful, thanks.
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)