How to reload a specific cell with out animation in swift 3? - ios

I am trying to like a post in a tableview, after getting response i need to update like status in my tableview without knowing to user that table is reloading.
let indexPath = IndexPath(item: tag, section: 0)
self.tableCommunity.reloadRows(at: [indexPath], with: .fade)

buddy try using code :-
let indexPath = IndexPath(item: tag, section: 0)
self.tableCommunity.reloadRows(at: [indexPath], with: .none)
Hope it will work.

Related

How to animate tableView cells when they change order?

I am currently working on a app that shows nearby annotations to user by TableView. Cells are ordered by distance to user's location. I want to animate the cells when they change order due to distance. How can I do that ?
Here's my view
I had tried this code but it didn't work.
tableView.beginUpdates()
tableView.moveRow(at: IndexPath(row: fromIndex, section: 0), to: IndexPath(row: toIndex, section: 0))
tableView.endUpdates()
Edit : I tried like this one it didn't work like the way I want, but it was really close. The problem is, all the cells are animating when a single cell changes it's order
didUpdateLocations :
sortedAnnotationArrayWithModel = annotationArrayWithModel.sorted { $0.distance < $1.distance }
tableView.reloadData()
tableView.beginUpdates()
for i in 0..<sortedAnnotationArrayWithModel.count {
let oldIndex = annotationArrayWithModel.firstIndex(of: sortedAnnotationArrayWithModel[i])
let newIndex = i
if oldIndex != newIndex {
tableView.moveRow(at: IndexPath(row: oldIndex!, section: 0), to: IndexPath(row: newIndex, section: 0))
}
}
tableView.endUpdates()
Try wrapping your changes in a call to performBatchUpdates(_:completion:)
You pass that function a closure that does the reordering, and it animates the changes.

Swift: Is it possible to not reload the first cell/row when using tableView.reloadData()?

I was wondering if it is posible to reload a tableView without reloading the first cell/row in a simple way? If so, how would you do it?
let itemArray:[Int] = []
for i in 1..<itemArray.count {
let indexPath = IndexPath(item: i, section: 0)
tableView.reloadRows(at: [indexPath], with: .fade)
}
If your table is not grouped currently ,
The best way to do this is add your 1st cell to one section And all other cells to another section. Then you can easily reload all cell excluding 1st cell using
//section 0 - your 1st cell
//section 1 - other cells
tableView.reloadSections([1], with: .none)
Just use the reloadRows method to reload your tableView.
var dataSource: [SomeData] = []
func reloadAllButFirstRow() {
guard dataSource.count > 0 else { return }
tableView.reloadRows(
at: (1...dataSource.count).map { IndexPath(row: $0, section: 0) },
with: .fade
)
}

Why tableview datasource not changing from Realm Collection observer?

I have the request to realm database
func allContacts() -> Results<RMContact> {
let realm = self.encryptedRealm()
return realm!.objects(RMContact.self).sorted(byKeyPath: "lastActive", ascending: false)
}
And code from presenter
DispatchQueue.main.async {
let contacts = RMContactsManager.shared.allContacts()
self.notificationToken = contacts.observe { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.view.tableView else { return }
switch changes {
case .initial:
UIView.performWithoutAnimation {
tableView.reloadData()
}
case .update(_, let deletions, let insertions, let modifications):
UIView.performWithoutAnimation {
tableView.beginUpdates()
tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }), with: .automatic)
tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}), with: .automatic)
tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }), with: .automatic)
tableView.endUpdates()
}
case .error(let error):
fatalError("\(error)")
}
}
}
After setting new lastActive value sequence in tableview didn't change
For the first time sorting is actual for the controller, but after setting new values to lastActive property no changes. Is it an observer problem?
The issue seems to be that you are getting changes in terms of insertions, deletions and modifications.
If you will first do the insertion and then deletion, (This is what you are doing right now), It will insert new values and the datasource will be modified so now when you delete the rows, it will not be correct.
Also in your case, where you are sorting the array, generally two elements will be replaced, one being deleted and other will be added.
So what can solve your problem is, first do deletions and then do insertions. Like this:
UIView.performWithoutAnimation {
tableView.beginUpdates()
tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}), with: .automatic)
tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }), with: .automatic)
tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }), with: .automatic)
tableView.endUpdates()
}

How to remove a cell from tableView with animation through IBAction? iOS Swift 3.0

I'm building a todo-list app, and I'm holding a task model array and tableView in my view controller.
Each cell in this tableView contains several UI elements, one of them is a UIView that is actually a checkbox, implemented by Skyscanner's pod:
https://github.com/Marxon13/M13Checkbox
I would like to remove a cell when a user tap on the checkbox (with animation).
I set an IBAction to the UIView, I know which element in the array I want to remove (I tagged each UIView) but I cannot use the method
tableView.deleteRows(at: [IndexPath], with: UITableViewRowAnimation)
since I don't have the index path.
I want to find a nice way to remove the cell with an index, preferably without holding an indexPath variable (I tried that but not sure how to implement it correctly since cells can be removed from various indexes).
Thanks for your help!
Thanks for everyone that helped!
I'm answering my own question because it was a combination of your answers!
as Puneet Sharma, Reinier Melian and Yun CHEN said, I managed to create an index path inside the function.
Puneet's comment is very important, you must remove the element from the array before you remove the cell.
PS.
Maybe I could create the IndexPath way before I even asked the question, but in the line
self.tableView.deleteRows(at: [IndexPath(row: checkbox.tag, section: 0)], with: .automatic)
Xcode does not auto complete this initialization at all.
This is the code that remove the cell just like I wanted:
#IBAction func completeBtnPressed(_ sender: Any) {
let checkbox = (sender as! M13Checkbox)
self.tasks.remove(at: checkbox.tag)
self.tableView.deleteRows(at: [IndexPath(row: checkbox.tag, section: 0)], with: .automatic)
}
Thanks a lot!
Set the action event on the checkbox/Button like bellow in cellForRowatIndexPath. don't forgot to add the tag on every checkbox/Button.
cell.btnCounter.tag = indexPath.row
cell.btnCounter.addTarget(self, action: #selector(self.buttonClicked), for: .touchUpInside)
You need to handle event as below
func buttonClicked(_ sender: UIButton) {
//Here sender.tag will give you the tapped checkbox/Button index from the cell
your_array.remove(at: sender.tag) //Remove your element from array
tableView.deleteRows(at: [IndexPath(row: sender.tag, section: 0))], with: .automatic) //Hope it is in section 0
}
Hope this help you
// Check this snap code
#IBAction func btnAction(_ sender : UIButton){
// get Indexpath with Button position
let buttonPosition = sender.convert(CGPoint.zero, to: self.tableview)
let indexPath: IndexPath? = tableview.indexPathForRow(at: buttonPosition)
self.yourArrayDatasource.remove(at: indexPath.row) // don't forget to replace your array of data source
self.tableview.deleteRows(at: [indexPath!], with: UITableViewRowAnimation.automatic)
}
I hope it help you

iOS TableView delay between adding new cells

I'm working with UITableView and I want to add new items once at a time instead of adding them all at one time when there are multiple new items. Right now, my code is like this:
for rowNum in 0...(counter-1) {
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {
self.tableView.insertRows(at: [IndexPath(row: rowNum, section: lastSection)], with: .fade)
}
}
But it's not working.
It's been a while but maybe I can help. While inserting new rows or sections, you need to use tableView.beginUpdates() and tableView.endUpdates(). Also, between these two functions, row numbers and the count of the array should be equal. Otherwise an error is thrown. Try this:
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {
self.tableView.beginUpdates()
self.<yourArray>.append(<newElement>)
self.tableView.insertRows(at: [IndexPath(row: self.<yourArray>.count - 1,
section: lastSection)], with: .fade)
self.tableView.endUpdates()
}

Resources