I have a tableview. The tableview cell contains images, labels. In this cell I have a button to delete the row. I want to animate the cell during deletion(ex. tinder like left or right swipe) or any animation to make the app actractive. How to do this type of animation. Or any recommended library ?
UITableViewCellEditingStyle will do the job for you for i.e
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
//do your necessary operations here
//reload your UITableView here
}
}
Swipe right to left to see the animation.
Typical Animation for your case :
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// your code
tableView.deleteRows(at: [indexPath], with: .automatic)
// your code
}
}
Alternate Way for custom Animation (Updated):
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .top) // Check (.)after for available animation example comment out below -
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .left)
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .right)
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .up)
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .down)
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .fade)
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .middle)
//tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], with: .bottom)
tableView.endUpdates()
Related
Try to delete tableViewCell in swift XIB. but there is error cannot remove models
viewModel :
private var combinedItems: [combinedInboxModel] = []
func get(){} // Add combinedItems data
View Controller
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
viewModel.combinedItems.remove(at: indexPath.row) // No exact matches in call to instance method 'remove' in swift
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
Why there is error remove here?
I am trying to delete data in my Firebase database and then listen for .childRemoved so I can update the TableView. I originally tried to remove the object from the array using the code below but got an index out of range error in cellForRowAt in indexPath.row.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let post = posts[indexPath.row]
posts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
DataService.ds.REF_POSTS.child(post.postKey).removeValue()
DataService.ds.REF_USERS.child("\(uid!)").child("posts").child("\(post.postKey)").removeValue()
//print("deleted post \(deletedPost)")
} else if editingStyle == .insert {
}
}
So, I decided to try to delete the Firebase data first and then listen at .childRemoved with the following combination of code (I commented out the removal of array objects in the editingStyle code).
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let post = posts[indexPath.row]
//posts.remove(at: indexPath.row)
//tableView.deleteRows(at: [indexPath], with: .fade)
DataService.ds.REF_POSTS.child(post.postKey).removeValue()
DataService.ds.REF_USERS.child("\(uid!)").child("posts").child("\(post.postKey)").removeValue()
//print("deleted post \(deletedPost)")
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
Then, I created a listener at .childRemoved in ViewDidLoad with the following.
newPost.observe(.childRemoved, with: { (snapshot) in
//print("CHILD REMOVED")
//print("\(self.posts)")
//print("\(snapshot.postKey)")
let postId = snapshot.key
if let indexNew = self.posts.firstIndex(where: {$0.postKey == postId}){
self.posts.remove(at: indexNew)
for n in 0...self.posts.count - 1 {
print("POST \(n) - \(self.posts[n])")
}
print("REMOVE INDEX - \(indexNew)")
print("POSTS AFTER REMOVAL - \(self.posts)")
self.feedTableView.reloadData()
}
}, withCancel: nil)
I am still receiving the index out of range error at cellForRowAt on indexPath.row. Am I on the right track with the second method? If so, what am I doing wrong to cause the out of range error?
EDIT: I am adding my cellForRowAt where I am getting the index out of range error and most updated commit editingStyle. I'm not sure how I am running over the array since the debug statements print
INDEX OF POST ARRAY - 2
POSTS: SocialSpirit.Post
POSTS AFTER DELETE [SocialSpirit.Post, SocialSpirit.Post, SocialSpirit.Post]
INDEX OF POST ARRAY - 0
Fatal error: Index out of range
And here is the code:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let post = posts[indexPath.row]
DataService.ds.REF_POSTS.child(post.postKey).removeValue()
DataService.ds.REF_USERS.child("\(uid!)").child("posts").child("\(post.postKey)").removeValue()
posts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
print("POSTS AFTER DELETE \(self.posts)")
//print("deleted post \(deletedPost)")
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("INDEX OF POST ARRAY - \(indexPath.row)")
print("POSTS: \(posts[indexPath.row])") //Index out of range error here
let post = posts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as? PostCell{
if let img = FeedViewController.imageCache.object(forKey: post.imageUrl as NSString) {
cell.configureCell(post: post, img: img)
} else {
cell.configureCell(post: post)
}
return cell
} else {
return PostCell()
}
}
The function this way removes the index error and correctly updates the tableView
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
let post = posts[indexPath.row]
DataService.ds.REF_USERS.child("\(uid!)").child("posts").child("\(post.postKey)").removeValue()
}
}
I want to refresh my conversations (table view cells) after deleting a conversation through a swipe action sheet.
I tried to reload the table view after deleting the data but it doesn't work. Also with a async.
// Swipe Action Sheet solution
func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
// Write action code for the Flag
let deleteAction = UIContextualAction(style: .normal, title: "Löschen", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
let ref = Database.database().reference()
ref.child("users").child((self.currentUser?.uid)!).child("conversations").child((self.items[indexPath.row].user.uid)!).removeValue()
DispatchQueue.main.async {
self.tableView.reloadData()
}
success(true)
})
deleteAction.backgroundColor = .red
return UISwipeActionsConfiguration(actions: [deleteAction])
}
Thanks in advance for your help!
You have to reload data in completion block of removeValue method if there isn't any error. Also before you reload data you have to remove item from items array
.removeValue { error,_ in
if error == nil {
self.items.remove(at: indexPath.row)
self.tableView.reloadData() // self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
success(error == nil)
}
To delete row using swipe, you can use
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
And because you not reload table view, that will look much better
I am using a table view which consists of three sections. User can delete the rows for third section. But while I am using table view delegate method for deleting rows ,It is affecting for other sections. So how could I overcome from this problem?
Here is my code
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
numbers.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
If you want to restrict editing to section 2 implement canEditRowAt (code is Swift 3+)
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return indexPath.section == 2
}
Or add a check
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete && indexPath.section == 2 {
numbers.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
In function with forRowAt indexPath: IndexPath you have IndexPath value.
It contains .section. So, you can simply check, which section have you selected and then do or not do deleting.
To delete rows for specific section:
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
Hope it helps
correct way of doing this is
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return indexPath.section == 2
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete && indexPath.section == 2
{
yourArray.remove(at: indexPath.row)
yourtable.reloadData()
}
}
I have a table of names and I am making a swipe and delete function for them which removes them from a names variable which is an array.
I selected the functions which most closely resembled the tutorial inside xcode and filled them out, but my app crashes randomly when I click the delete button. Here is my code for the delete button:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete") { (rowAction: UITableViewRowAction, indexPath: IndexPath) -> Void in
print("Deleted")
self.catNames.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
self.tableView.reloadData()
}
}
I'm new to coding and learning swift, I am following a tutorial for swift 2 and working with swift 3 so there are a few issues I have when following along, this being one I'm properly stuck on.
Works for Swift 3 and Swift 4
Use the UITableViewDataSource tableView(:commit:forRowAt:) method, see also this answer here:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.catNames.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
First you need to add this function
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
then your function is ok but no need of tableview reload data just call tableview.beingUpdates and tableview.endUpdates
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.catNames.remove(at: indexPath.row)
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .automatic)
self.tableView.endUpdates()
}
}
In Swift 4 Try This
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
arrStudentName.remove(at: indexPath.row)
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .middle)
tableView.endUpdates()
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.animals.remove(at: indexPath.row)
self.dataDisplayTbleView.reloadData()
}
}
**
for swift 3
**
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.catNames.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
My answer for you
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete
{
array.remove(at: indexPath.row)
tblDltRow.reloadData()
}
}
You need to refresh the table
You don't have to reload the tableView.
Before you use tableView.deleteRows(at: [IndexPath], with: UITableView.RowAnimation) you must substrate the number of rows you want delete in numberOfRowsInSection
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return //Your current number of rows - The number of rows to delete
}
Normally the number of rows is the number of Items from an array (yourArray.count), that means you can delete the items from this array before you delete the cells and you get the same result.
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [ IndexPath(row: index, section: section) ], with: .fade)
self.remove_object_from_model()
self.tableView.endUpdates()
For Swift 5
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.catNames.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}