Tableview doesn't edit on swipe action - ios

I'm trying to implement the ability to edit the order of the tableview cells in my app. To do this, the user swipes right and taps on an edit button. However, when the edit button is tapped, the tableview doens't begin editing.
Below is my code:
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let edit = UIContextualAction(style: .normal, title: "Edit") { (UIContextualAction, UIView, complete: # escaping (Bool) -> Void) in
self.toggleTableViewEditing()
self.editEnabled()
complete(true)
}
return UISwipeActionsConfiguration(actions: [edit])
}
func editEnabled() {
if tableView.isEditing == true {
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(toggleTableViewEditing))
} else {
navigationItem.rightBarButtonItem = nil
}
}
#objc func toggleTableViewEditing() {
tableView.isEditing = !tableView.isEditing
editEnabled()
}
Once the edit button is tapped, the edit button dismisses but the tableview doesn't enter the .isEditing state like it should.

You can use editActionsForRowAt function :
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editAction = UITableViewRowAction(style: .default, title: "Edit") { (action, index) in
// your edit action here
}
return [editAction]
}
I made an app like this and its work well.

Related

Change "Delete Text" on Swipe Eureka

Is there a way to change the text of the ContextualAction so it doesn't say "delete" anymore?
You can simply create delegate method, trailingSwipeActionsConfigurationForRowAt like below and customise it as you want:
extension YOURVIEWCONROLLER: UITableViewDelegate{
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let removeAction = UIContextualAction(style: .destructive, title: "Remove") { action, view, complete in
//Your code
Utility.main.showAlert(message: "Removed Pressed", title: "Alert")
complete(true)
}
doneAction.backgroundColor = UIColor.red
return UISwipeActionsConfiguration(actions: [removeAction])
}
}
Or
In Core.swift file you need to edit its function.

How to enable Leading and Trailing Swipe with Drag and Drop UITableview Cell Swift

I am trying to enable Leading and Trailing swipe with Long press tableview cell to drag and drop option using Swift. Here, I am using below code I can able to drag and drop it but can’t able to do long press also can't able to enable leading and trailing swipe at a time. Three things need to enable by default when app launched.
Tableview Delegate
override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .normal, title: "Delete", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("OK, marked as Delete")
success(true)
})
deleteAction.backgroundColor = .orange
return UISwipeActionsConfiguration(actions: [deleteAction])
}
override func tableView(_ tableView: UITableView,trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let modifyAction = UIContextualAction(style: .normal, title: "Edit", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("Update action ...")
self.showaddMilestone()
success(true)
})
modifyAction.image = UIImage(named: "edit")
modifyAction.backgroundColor = .red
return UISwipeActionsConfiguration(actions: [modifyAction])
}
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = self.milestoneTitles[sourceIndexPath.row]
milestoneTitles.remove(at: sourceIndexPath.row)
milestoneTitles.insert(movedObject, at: destinationIndexPath.row)
debugPrint("\(sourceIndexPath.row) => \(destinationIndexPath.row)")
// To check for correctness enable: self.tableView.reloadData()
}
You can do this in following way...
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
#available(iOS 11.0, *)
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
//EDIT
let actionEDIT = UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in
//do stuff
completionHandler(true)
})
actionEDIT.image = UIImage(named: "icn_edit")
actionEDIT.backgroundColor = UIColor.UIColorFromHex(hex: "F7F7F7")
//PDF
let actionPDF = UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in
//do stuff
completionHandler(true)
})
actionPDF.image = UIImage(named: "icn_pdf")
actionPDF.backgroundColor = UIColor.UIColorFromHex(hex: "F7F7F7")
//SHARE
let actionSHARE = UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in
//do stuff
completionHandler(true)
})
actionSHARE.image = UIImage(named: "icn_shareGreen")
actionSHARE.backgroundColor = UIColor.UIColorFromHex(hex: "F7F7F7")
let configuration = UISwipeActionsConfiguration(actions: [actionSHARE,actionPDF,actionEDIT])
return configuration
}
// leftAction Leading
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let leftAction = UIContextualAction(style: .normal, title: "Edit", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("leftAction tapped")
success(true)
})
leftAction.image = UIImage(named: "")
leftAction.backgroundColor = UIColor.red
return UISwipeActionsConfiguration(actions: [leftAction])
}
Here's something that works for me but I'm not sure if it's correct and will always work in future
final class ViewController: UITableViewController {
private let data: [String] = [
"1", "2", "3", "4", "5"
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dragInteractionEnabled = true
tableView.dragDelegate = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .value1, reuseIdentifier: "cell")
cell.detailTextLabel?.text = data[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
}
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completion ) in
completion(true)
}
return UISwipeActionsConfiguration(actions: [delete])
}
}
extension ViewController: UITableViewDragDelegate {
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
return []
}
}

Swift create left, right swipe with long press tableview row cell movable

In my scenario, I am trying to create a UITableView cell enable left and right swipe with tableView cell long-press to movable within in particular section. Here, I can only able to do trailing and leading swipe, don't know how to move cells within a section.
Below Code For Leading and Trailing
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .normal, title: "Delete", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("OK, marked as Delete")
success(true)
})
if #available(iOS 13.0, *) {
deleteAction.image = UIImage(systemName: "delete")
} else {
// Fallback on earlier versions
deleteAction.image = UIImage(named: "delete")
}
deleteAction.backgroundColor = .red
return UISwipeActionsConfiguration(actions: [deleteAction])
}
func tableView(_ tableView: UITableView,trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let modifyAction = UIContextualAction(style: .normal, title: "Edit", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("Update action ...")
self.showaddMilestone()
success(true)
})
modifyAction.image = UIImage(named: "edit")
modifyAction.backgroundColor = .green
return UISwipeActionsConfiguration(actions: [modifyAction])
}
a) enable drag interation on table view
b) set drag and drop delegates
tableView.dragInteractionEnabled = true
tableView.dragDelegate = self
tableView.dropDelegate = self
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath:
IndexPath, to destinationIndexPath: IndexPath) { }
extension TableView: UITableViewDropDelegate,UITableViewDragDelegate {
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
return [UIDragItem(itemProvider: NSItemProvider())]
}
func tableView(_ tableView: UITableView, dropSessionDidUpdate session:
UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?)
-> UITableViewDropProposal {
if session.localDragSession != nil {
return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UITableViewDropProposal(operation: .cancel, intent: .unspecified)
}
func tableView(_ tableView: UITableView, performDropWith coordinator:
UITableViewDropCoordinator) {
}
}

UITableView editActionsForRowAt not reacting properly to nil in Swift 5

I have had a UITableView working for several version of Swift, but with Swift 5, it started presenting 'delete' action on a left swipe.
One of the rows is 'swipe-able' (the 'Expanded' one) and others are not, so I return a nil in place of the RowAction.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
if listOfCurrentAwards[indexPath.row] != "Expanded" {
print(">>> Skipping row \(indexPath.row)")
return nil
} else {
let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
self.prepareOneDogMessageShareSheet(row: indexPath.row)
}
share.backgroundColor = UIColor.blue
return [share]
}
}
I am also getting the same behavior with the older 'editActionsForRowAtIndexPath'.
Anyone else seeing the same thing? Did you find a work around?
For now I am just returning a dummy action that displays a dog related emoji ().
if listOfCurrentAwards[indexPath.row] != "Expanded" {
//TBD - remove the following line if the nill action is supported/fixed.
let dogEmoji = ["🐢","🐩","🦴","πŸ•","πŸ’©","🐾"]
let share = UITableViewRowAction(style: .normal, title: dogEmoji.randomElement()) { action, index in
print(">>> Skipping row \(indexPath.row)")
}
return [share] //nil
} else ...
Update 1
Even refactoring to use trailingSwipeActionsConfigurationForRowAt did not work, I'm getting the same result.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
if listOfCurrentAwards[indexPath.row] != "Expanded" {
print(">>> Swiping not enabled for row \(indexPath.row)")
return nil
} else {
print(">>> 'Share' swipped on \(indexPath.row)")
let shareAction = UIContextualAction(style: .normal, title: "Share") { (action, view, handler) in
print(">>> 'Share' clicked on \(indexPath.row)")
self.prepareOneDogMessageShareSheet(row: indexPath.row)
}
shareAction.backgroundColor = UIColor.blue
let configuration = UISwipeActionsConfiguration(actions: [shareAction])
configuration.performsFirstActionWithFullSwipe = true //false to not support full swipe
return configuration
}
}
Answer
I had to add the canEditRowAt helper, allow me to move some of the logic from trailingSwipeActionsConfigurationForRowAt.
func tableView(_ tableView: UITableViewbcgdfgdfg, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?vdfgh
{
print(">>> Trying to swipe row \(indexPath.row)")
let shareAction = UIContextualAction(style: .normal, title: "Share") { (action, view, handler) in
print(">>> 'Share' clicked on \(indexPath.row)")
self.prepareOneDogMessageShareSheet(row: indexPath.row)
}
shareAction.backgroundColor = UIColor.blue
let configuration = UISwipeActionsConfiguration(actions: [shareAction])
return configuration
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return listOfCurrentAwards[indexPath.row] == "Expanded"
}
editActionsForRowAt is outmoded if the goal is to control what happens when you swipe. So is UITableViewRowAction.
You should be using tableView(_:trailingSwipeActionsConfigurationForRowAt:).

Adding swipe button in table view in swift

I have a simple table view showing a list of tasks. I want to show two buttons when user swipes on a cell. A delete button to delete the cell and Completed button to store the task in completed array. I am able to implement the delete button but no idea of showing a second button in the table cell. here is the code.
import UIKit
var taskArray = [String]()
var datesArray = [String]()
class ViewController: UIViewController, UITableViewDataSource
{
#IBOutlet weak var taskTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return taskArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell", for: indexPath)
cell.textLabel?.text = "\(indexPath.row + 1). \(taskArray[indexPath.row])"
cell.detailTextLabel?.text = datesArray[indexPath.row]
return cell
}
override func viewDidLoad()
{
super.viewDidLoad()
taskTableView.dataSource = self
let userDefaults = UserDefaults.standard
if let task = userDefaults.stringArray(forKey: "tasks") , let date = userDefaults.stringArray(forKey: "dates")
{
taskArray = task
datesArray = date
}
print(taskArray)
print(datesArray)
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
taskTableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// this method handles row deletion
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete
{
// remove the item from the data model
taskArray.remove(at: indexPath.row)
datesArray.remove(at: indexPath.row)
// delete the table view row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
//function to come back from close button
#IBAction func close(segue: UIStoryboardSegue)
{
}
}
Swift 4.0
You can write below method of tableView to define custom swipe action.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .default, title: "Delete") { (action, indexPath) in
}
delete.backgroundColor = UIColor.red
let complete = UITableViewRowAction(style: .default, title: "Completed") { (action, indexPath) in
// Do you complete operation
}
complete.backgroundColor = UIColor.blue
return [delete, complete]
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
//self.isEditing = false
print("more button tapped")
}
more.backgroundColor = UIColor.lightGray
let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
//self.isEditing = false
print("favorite button tapped")
}
favorite.backgroundColor = UIColor.orange
let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
//self.isEditing = false
print("share button tapped")
}
share.backgroundColor = UIColor.blue
return [share, favorite, more]
}
First make this function return true
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
return true
}
it makes your cell editable , apple provides default deleting and editing options that you can use as like this :
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if(editingStyle == .delete)
{
myArray.remove(at: indexPath.item)
table.deleteRows(at: [indexPath], with: .automatic)
table.reloadData()
}
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
if(studentUser as? String == "Admin")
{
return .delete
}
else
{
return .none
}
}
or you can define your custom ones :
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
let del = UITableViewRowAction(style: .normal, title: "Delete")
{
(action, index) in
let alert = FCAlertView()
alert.makeAlertTypeCaution()
alert.cornerRadius = 10
alert.delegate = self
alert.animateAlertInFromBottom = true
alert.animateAlertOutToTop = true
alert.bounceAnimations = true
alert.blurBackground = true
alert.dismissOnOutsideTouch = true
alert.showAlert(inView: self,
withTitle: "Title you want ",
withSubtitle: "Subtitle Comes here",
withCustomImage: nil,
withDoneButtonTitle:"OK" ,
andButtons:["Cancel"])
}
let edit = UITableViewRowAction(style: .default, title: "Edit")
{
(action, index) in
self.view.makeToast("Editing Coming soon...")
}
del.backgroundColor = AppColor.myNewRedColor
edit.backgroundColor = .lightGray
return [edit,del]
}
Swift 4.0
Add Delegate & DataSource
tableView.delegate = self
tableView.dataSource = self
Add DataSource func "canEditRowAt indexPath"
//MARK: - UITableViewDataSource
public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
Add Delegate func "editActionsForRowAt indexPath"
//MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editAction = UITableViewRowAction(style: .default, title: "Edit", handler: { (action, indexPath) in
//Action edit
print("Action Edit...")
})
editAction.backgroundColor = UIColor.gray //Set button color
let deleteAction = UITableViewRowAction(style: .default, title: "Delete", handler: { (action, indexPath) in
//Action delete
print("Action Delete...")
})
return [deleteAction, editAction]
}
I hope this helps.
As par your Requirement i have . created Demo for you.
Here is the Output,
When you press Delete element will be removed from Array and when you press Add Button element will be added to new Array.
Here is the link of Demo,
Tableview Demo with Swipable Add and Delete
Step 1:- Connect your Tableview datasource and delegate in Storyboard.
Step 2:- Write DataSource Methods of TableView.
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Preloaded Data"
} else {
return "Added Data to New Array"
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return arrPrelodedData.count
} else {
return arrAddNewData.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "SwipeToDelete", for: indexPath) as? SwipeToDelete else {return UITableViewCell()}
if indexPath.section == 0{
cell.lblCellContent.text = arrPrelodedData[indexPath.row] }
else {
cell.lblCellContent.text = arrAddNewData[indexPath.row]
}
return cell
}
//With this we can edit UITableview ex. Swipe to Delete
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
if indexPath.section == 0 {
return true } else {
return false
}
}
//Select tableview Editing Style (insert and Delete)-> if custom icon than set None
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.none
}
//Delete Action 1) Create delete Action 2) Remove data with Indexpath 3) fetch data from coredata 4) delete tableview row 4) set delete button background color 5) return deleteAction in arry wether it is single
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
//Destructive Because we want to delete(destroy) the data from tableview
let deleteAction = UITableViewRowAction(style: .destructive, title: "DELETE") { (rowAction, indexpath) in
self.arrPrelodedData.remove(at: indexPath.row)
tableView.deleteRows(at: [indexpath], with: .automatic)
}
let addAction = UITableViewRowAction(style: .normal, title: "ADD 1") { (rowAction, indexpath) in
self.arrAddNewData.append(self.arrPrelodedData[indexPath.row])
tableView.reloadSections(NSIndexSet(index: 1) as IndexSet, with: .none)
// tableView.reloadRows(at: [indexPath], with: .automatic)
}
deleteAction.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
addAction.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.662745098, blue: 0.2666666667, alpha: 1)
return [deleteAction,addAction]
}
}
I hope this answer will helpful for you.

Resources