In my iOS app I have a UITableViewController whose rows contain data and data picker. I want to change te function of the buttons Edit and Done. I would like the Edit button to allow the user to write/insert data (instead of deleting rows), while I would like the Done button to save to save the data (and not just exiting the edit mode). I've added to my code the following:
// The following two functions remove the red minus sign
override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.None
}
override func tableView(tableView: UITableView, shouldIndentWhileEditingRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
in order to avoid appearing the circle red minus, but how can I override the functions according to Edit or Done value of the button? I heard about delegates but I'm new to iOS and I don't know what they are...if someone can explain me I would be grateful.
Please try this code block :-)
import UIKit
// You can initialise an instance of this class manually or configure it on storyboard
class TableViewController: UITableViewController {
// MARK:- This part is for demo purpose
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.backgroundColor = UIColor.yellowColor()
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
// MARK:- From here is the main part to answer your question
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, shouldIndentWhileEditingRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let editAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Edit") { (action, indexPath) -> Void in
print("Write/Insert data here")
}
let doneAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Done") { (action, indexPath) -> Void in
print("Save data here")
}
doneAction.backgroundColor = UIColor.blueColor()
return [doneAction, editAction]
}
}
You will see the result like this
Related
New iOS 11 UITableView Swipe action not getting called. The delegate and datasource are working fine for the table.
I am not able to swipe and see the menu items.
Below is my code for the same.
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let contextItem = UIContextualAction(style: .normal, title: "Leading & .normal") { (contextualAction, view, boolValue) in
print("Leading Action style .normal")
}
let swipeActions = UISwipeActionsConfiguration(actions: [contextItem])
return swipeActions
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let contextItem = UIContextualAction(style: .destructive, title: "Trailing & .destructive") { (contextualAction, view, boolValue) in
print("Trailing Action style .destructive")
}
let swipeActions = UISwipeActionsConfiguration(actions: [contextItem])
return swipeActions
}
I tried to call below and its working fine.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
}
}
Any hint in right direction is highly appreciated.
You need to pass true to UIContextualAction in the closure boolValue(true). Otherwise the handler won't allow the action.
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let contextItem = UIContextualAction(style: .normal, title: "Leading & .normal") { (contextualAction, view, boolValue) in
boolValue(true) // pass true if you want the handler to allow the action
print("Leading Action style .normal")
}
let swipeActions = UISwipeActionsConfiguration(actions: [contextItem])
return swipeActions
}
For those who uses UITableViewDiffableDataSource you need to subclass it and override its canEditRowAt method.
public override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
true
}
Code looks good, but you are missing probably missing the following the "UITableViewDelegate" in the Class declaration and also the "TableView.delegate = self" in the viewdidload() section. So it should look like:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
}
I have a UITableView inside a UIViewController. I am trying to make it so when the user click the BarButtonItem in the NavigationBar, that the tableview goes into editing mode, and thus the user can drag and reorder the cells.
However, what happens is that I simply press the editing button, and nothing happens.
This is what I have tried:
For the array declaration:
var tester = ["1", "2", "3"]
For the button declaration:
#IBAction func editButtonPressed(sender: AnyObject) {
self.editing = !self.editing
}
For the various tableview functions:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return tester.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("editCell", forIndexPath: indexPath) as! EditTableViewCell
cell.nameHolder?.text = tester[indexPath.row]
// Configure the cell...
return cell
}
func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
var itemToMove = tester[fromIndexPath.row]
tester.removeAtIndex(fromIndexPath.row)
tester.insert(itemToMove, atIndex: toIndexPath.row)
}
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
What could be causing this bug?
Swift 4.1
In → func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
Add this line to configure the cell:
cell.isEditing = self.tableView(tableView, canMoveRowAt: indexPath)
Ran Hassid has the most correct answer to this in his comment.
This will solve the problem:
#IBOutlet weak var tableView: UITableView!
#IBAction func editButtonPressed(sender: AnyObject) {
tableView.setEditing(!tableView.isEditing, animated: true)
}
As you can see in the images, there are two sections in this tableView.
May I know how to manage to enable the editActionsForRowAtIndexPath in section one only?
Here is my code that enable the tableViewCell to have a row swipe...
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]?
{
let complete = UITableViewRowAction(style: .Normal, title: "Complete")
{ action, index in
print("more button tapped")
}
complete.backgroundColor = UIColor.greenColor()
return [complete]
}
You can use indexPath.section to decide which section you are setting, but you should use tableView:canEditRowAtIndexPath:indexPath: to tell the table view when you want to enable editing.
Swift 2
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool{
return indexPath.section == 0
}
Swift 3
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return indexPath.section == 0
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var items = ["foo", "bar", "baz", "mamma mia"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.editing = true
navigationItem.leftBarButtonItem = editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(table1: UITableView,
numberOfRowsInSection section: Int)
-> Int {
return self.items.count
}
// `UITableViewCell`s for each section and row
func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let item = self.items[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = item
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
print ("at editing style")
if editingStyle == .Delete {
print ("delete at row: \(indexPath.row)")
}
if editingStyle == .Insert {
print ("insert at row: \(indexPath.row)")
}
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// print ("at can edit row: \(indexPath.row)")
return true
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
}
}
why is the menu/delete buttons not appearing?
if (when) they do appear, are they processed at commitEditingStyle?
Implement this method:
func tableView(tableView: UITableView!, editingStyleForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCellEditingStyle {
return .Delete
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let shareAction = UITableViewRowAction(style: .Normal, title: "Share") { (action, indexPath) -> Void in
// tableView.editing = false
print("shareAction")
}
let deleteAction = UITableViewRowAction(style: .Normal, title: "Delete") { (action, indexPath) -> Void in
// tableView.editing = false
print("deleteAction")
}
// shareAction.backgroundColor = UIColor.grayColor()
return [deleteAction, shareAction]
}
I have UIviewController which contains a UITableView , it's a very simple code , I just want to swipe one cell and show more and delete and handle these two events , this is my very simple class
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
let deleteClosure = { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
println("Delete closure called")
}
let moreClosure = { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
println("More closure called")
}
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]?
{
var moreAction = UITableViewRowAction(style: .Default , title: "More") { (action : UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
println("more")
}
moreAction.backgroundColor = UIColor.lightGrayColor()
var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action: UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
println("delete")
}
return [moreAction , deleteAction]
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
{
if (editingStyle == .Delete)
{
println("delete1")
}
if(editingStyle == .Insert)
{
println("insert")
}
}
the editActionsForRowAtIndexPath function get called but none of the RowActions shows up !
what's the problem ? ,
you need to do something in the handlers of your custom buttons.
For example, with a custom delete button (and just to change its label and background color), you would do somehting like:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
let button = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: NSLocalizedString("TitleOfDeleteButton", comment: "Delete"), handler: { (rowAction, indexPath) -> Void in
self.tableView(self.tableView!, commitEditingStyle: UITableViewCellEditingStyle.Delete, forRowAtIndexPath: indexPath)
})
button.backgroundColor = UIColor.lightGrayColor()
return [button]
}
Also, don't forget that this method of the UITableViewDelegate protocol came only with iOS8