Custom edit view in UITableViewCell while swipe left. Objective-C or Swift

129,156

Solution 1

Just copy paste the code below!

-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewRowAction *editAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"Clona" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
       //insert your editAction here
    }];
    editAction.backgroundColor = [UIColor blueColor];
    
    UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"Delete"  handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
       //insert your deleteAction here
    }];
    deleteAction.backgroundColor = [UIColor redColor];
    return @[deleteAction,editAction];
}

Solution 2

Swift 3

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    let editAction = UITableViewRowAction(style: .normal, title: "Edit") { (rowAction, indexPath) in
        //TODO: edit the row at indexPath here
    }
    editAction.backgroundColor = .blue

    let deleteAction = UITableViewRowAction(style: .normal, title: "Delete") { (rowAction, indexPath) in
        //TODO: Delete the row at indexPath here
    }
    deleteAction.backgroundColor = .red

    return [editAction,deleteAction]
}

Swift 2.1

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let editAction = UITableViewRowAction(style: .Normal, title: "Edit") { (rowAction:UITableViewRowAction, indexPath:NSIndexPath) -> Void in
        //TODO: edit the row at indexPath here
    }
    editAction.backgroundColor = UIColor.blueColor()

    let deleteAction = UITableViewRowAction(style: .Normal, title: "Delete") { (rowAction:UITableViewRowAction, indexPath:NSIndexPath) -> Void in
        //TODO: Delete the row at indexPath here
    }
    deleteAction.backgroundColor = UIColor.redColor()

    return [editAction,deleteAction]
}

Note: for iOS 8 onwards

Solution 3

You can use UITableViewRowAction's backgroundColor to set custom image or view. The trick is using UIColor(patternImage:).

Basically the width of UITableViewRowAction area is decided by its title, so you can find a exact length of title(or whitespace) and set the exact size of image with patternImage.

To implement this, I made a UIView's extension method.

func image() -> UIImage {
    UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
    guard let context = UIGraphicsGetCurrentContext() else {
        return UIImage()
    }
    layer.render(in: context)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image!
}

and to make a string with whitespace and exact length,

fileprivate func whitespaceString(font: UIFont = UIFont.systemFont(ofSize: 15), width: CGFloat) -> String {
    let kPadding: CGFloat = 20
    let mutable = NSMutableString(string: "")
    let attribute = [NSFontAttributeName: font]
    while mutable.size(attributes: attribute).width < width - (2 * kPadding) {
        mutable.append(" ")
    }
    return mutable as String
}

and now, you can create UITableViewRowAction.

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let whitespace = whitespaceString(width: kCellActionWidth)
    let deleteAction = UITableViewRowAction(style: .`default`, title: whitespace) { (action, indexPath) in
        // do whatever you want
    }

    // create a color from patter image and set the color as a background color of action
    let kActionImageSize: CGFloat = 34
    let view = UIView(frame: CGRect(x: 0, y: 0, width: kCellActionWidth, height: kCellHeight))
    view.backgroundColor = UIColor.white
    let imageView = UIImageView(frame: CGRect(x: (kCellActionWidth - kActionImageSize) / 2,
                                              y: (kCellHeight - kActionImageSize) / 2,
                                              width: 34,
                                              height: 34))
    imageView.image = UIImage(named: "x")
    view.addSubview(imageView)
    let image = view.image()

    deleteAction.backgroundColor = UIColor(patternImage: image)

    return [deleteAction]
}

The result will look like this.

enter image description here

Another way to do this is to import custom font which has the image you want to use as a font and use UIButton.appearance. However this will affect other buttons unless you manually set other button's font.

From iOS 11, it will show this message [TableView] Setting a pattern color as backgroundColor of UITableViewRowAction is no longer supported.. Currently it is still working, but it wouldn't work in the future update.

==========================================

For iOS 11+, you can use:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
  let deleteAction = UIContextualAction(style: .normal, title: "Delete") { (action, view, completion) in
    // Perform your action here
      completion(true)
  }

  let muteAction = UIContextualAction(style: .normal, title: "Mute") { (action, view, completion) in
    // Perform your action here
    completion(true)
  }

  deleteAction.image = UIImage(named: "icon.png")
  deleteAction.backgroundColor = UIColor.red
  return UISwipeActionsConfiguration(actions: [deleteAction, muteAction])
} 

Solution 4

You Can try this,

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    let backView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
    backView.backgroundColor = #colorLiteral(red: 0.933103919, green: 0.08461549133, blue: 0.0839477703, alpha: 1)

    let myImage = UIImageView(frame: CGRect(x: 30, y: backView.frame.size.height/2-14, width: 16, height: 16))
    myImage.image = #imageLiteral(resourceName: "rubbish-bin")
    backView.addSubview(myImage)

    let label = UILabel(frame: CGRect(x: 0, y: myImage.frame.origin.y+14, width: 80, height: 25))
    label.text = "Remove"
    label.textAlignment = .center
    label.textColor = UIColor.white
    label.font = UIFont(name: label.font.fontName, size: 14)
    backView.addSubview(label)

    let imgSize: CGSize = tableView.frame.size
    UIGraphicsBeginImageContextWithOptions(imgSize, false, UIScreen.main.scale)
    let context = UIGraphicsGetCurrentContext()
    backView.layer.render(in: context!)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    let delete = UITableViewRowAction(style: .destructive, title: "           ") { (action, indexPath) in
        print("Delete")
    }

    delete.backgroundColor = UIColor(patternImage: newImage)

    return [delete, share]
}

Solution 5

Refer this link : https://github.com/TeehanLax/UITableViewCell-Swipe-for-Options

And customize your uitableviewcell with multiple button.

 UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds) + kCatchWidth, CGRectGetHeight(self.bounds));
scrollView.delegate = self;
scrollView.showsHorizontalScrollIndicator = NO;

[self.contentView addSubview:scrollView];
self.scrollView = scrollView;

UIView *scrollViewButtonView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) - kCatchWidth, 0, kCatchWidth, CGRectGetHeight(self.bounds))];
self.scrollViewButtonView = scrollViewButtonView;
[self.scrollView addSubview:scrollViewButtonView];

// Set up our two buttons
UIButton *moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
moreButton.backgroundColor = [UIColor colorWithRed:0.78f green:0.78f blue:0.8f alpha:1.0f];
moreButton.frame = CGRectMake(0, 0, kCatchWidth / 3.0f, CGRectGetHeight(self.bounds));
[moreButton setTitle:@"More" forState:UIControlStateNormal];
[moreButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[moreButton addTarget:self action:@selector(userPressedMoreButton:) forControlEvents:UIControlEventTouchUpInside];

[self.scrollViewButtonView addSubview:moreButton];

UIButton *shareButton = [UIButton buttonWithType:UIButtonTypeCustom];
shareButton.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:1.0f];
shareButton.frame = CGRectMake(kCatchWidth / 3.0f, 0, kCatchWidth / 3.0f, CGRectGetHeight(self.bounds));
[shareButton setTitle:@"Share" forState:UIControlStateNormal];
[shareButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[shareButton addTarget:self action:@selector(userPressedMoreButton:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollViewButtonView addSubview:shareButton];

UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
deleteButton.backgroundColor = [UIColor colorWithRed:1.0f green:0.231f blue:0.188f alpha:1.0f];
deleteButton.frame = CGRectMake(kCatchWidth / 3.0f+kCatchWidth / 3.0f, 0, kCatchWidth / 3.0f, CGRectGetHeight(self.bounds));
[deleteButton setTitle:@"Delete" forState:UIControlStateNormal];
[deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[deleteButton addTarget:self action:@selector(userPressedDeleteButton:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollViewButtonView addSubview:deleteButton];

UIView *scrollViewContentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
scrollViewContentView.backgroundColor = [UIColor whiteColor];
[self.scrollView addSubview:scrollViewContentView];
self.scrollViewContentView = scrollViewContentView;

UILabel *scrollViewLabel = [[UILabel alloc] initWithFrame:CGRectInset(self.scrollViewContentView.bounds, 10, 0)];
self.scrollViewLabel = scrollViewLabel;
[self.scrollViewContentView addSubview:scrollViewLabel];
  • I have implemented this code with my app got such result. You can add number of button in swipe cell.

    Here is implemented screen shots

    enter image description hereAfter swipe the cell 3 buttons appears "More","Share","Delete".

Share:
129,156

Related videos on Youtube

ugoarangino
Author by

ugoarangino

18, blogger, software developer, german and italian

Updated on October 23, 2021

Comments

  • ugoarangino
    ugoarangino over 2 years

    How to make a custom edit view in iOS7 UITableView with Objective C like the Evernote or the Apple Reminders app while swipe left. I have tried to set an custom editingAccessoryView, but this didn't work.

    Evernote edit view:

    enter image description here Reminders edit view:

    enter image description here

    My current code is

    - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
        return YES;
    }
    
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
        if (editingStyle == UITableViewCellEditingStyleDelete) {
            NSLog(@"delete");
        }
    }
    

    I have tried to solve the problem with: (UITableViewController.h)

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        //make cell
    
        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        [view setBackgroundColor:[UIColor greenColor]];
        //add Buttons to view
    
        cell.editingAccessoryView = view;
    
        return cell;
    }
    

    And the same with: (UITableViewCell)

    - (void)willTransitionToState:(UITableViewCellStateMask)state;
    - (void)setEditing:(BOOL)editing animated:(BOOL)animated;
    - (UIView*)editingAccessoryView;
    
    • Suhas Arvind Patil
      Suhas Arvind Patil over 4 years
      can we make the height fix for the side swipe buttons? eg: my cell is 150 and i want button to be show only 50.0f is it possible?
  • u2Fan
    u2Fan almost 9 years
    To get these to show up in my case, I also needed to implement the table view's dataSource method - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath; Even an empty implementation of this method was sufficient to get the buttons to show up.
  • MattyG
    MattyG over 8 years
    I've converted this to Swift and posted it as a new answer below. stackoverflow.com/a/33748345/470879
  • Kartik 123
    Kartik 123 over 8 years
    @sohil which image? you are having an imageview in your cell? So you are getting a handler in that method which i have written which will be called when you tap on any of the buttons
  • Jerland2
    Jerland2 about 7 years
    Could you clarrify the func image() -> UIImage {} I have errors ebcause there is no varaible bounds.size in its first line. likewise in the 5th line hthere is no layer variable... Since the function does not take in any variables. Thank you
  • Ryan
    Ryan about 7 years
    That is an 'UIView''s extension. So bounds will be the instance's bounds.
  • Jerland2
    Jerland2 about 7 years
    THIS IS AWESOME, exactly what I was looking for. Very creative implementation, love it! Thank you
  • mythicalcoder
    mythicalcoder about 7 years
    but the swipe is NOT having any effect !! in swift3 Any other methods needed ?
  • mythicalcoder
    mythicalcoder about 7 years
    swift 3 - Swipe doesn't seem to work !! No options are shown !!
  • MattyG
    MattyG about 7 years
    @Maven, have you implemented canEditRowAtIndexPath to return true?
  • TheCodingArt
    TheCodingArt about 7 years
    FYI, you shouldn't be using init directly: deleteAction.backgroundColor = UIColor.init(patternImage: image) should be deleteAction.backgroundColor = UIColor(patternImage: image). Awesome answer though
  • mattsson
    mattsson about 7 years
    This doesn't attempt to answer the question. The submitter specifically asked how to set icons for the swipe actions instead of text.
  • MattyG
    MattyG about 7 years
    @mattsson, the question is vague in that regard, and doesn't mention icons at all. It mentions Evernote and Apple Reminders as examples. The Apple Reminders app uses a standard implementation like this answer.
  • mattsson
    mattsson about 7 years
    @MattyG You're completely right, I don't know what I was thinking.
  • reojased
    reojased about 7 years
    I've noticed you also need to at least write func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { } or editActionsForRowAtIndexPath won't be called
  • krlbsk
    krlbsk almost 7 years
    Great answer. Thanks a lot!
  • nyxee
    nyxee almost 7 years
    tableView(_, commit:, forRowAt:) { } as mentioned above
  • Jan
    Jan almost 7 years
    how to add images instead of text?
  • Travis M.
    Travis M. over 6 years
    This solution was exactly what I was looking for but unfortunately, it will only work for very small images because the "whitespace" padding no longer increases the size past the minimum width. I tried a non-breaking space \u{00a0} but it still is always the minimum size. I wonder if there's another unicode character that's blank that actually takes up space?
  • Legonaftik
    Legonaftik over 6 years
    Isn't there a memory leak when you create a closure which references to self?
  • Harshith Rai
    Harshith Rai over 5 years
    would be nice if you added some explanation in the answer itself buddy.
  • Majid Bashir
    Majid Bashir almost 5 years
    what about from iOS 9 and above ?
  • Vinay Kharb
    Vinay Kharb almost 5 years
    @MajidBashir My apps do not support the older iOS versions. Sorry, unable to help.
  • James Wolfe
    James Wolfe almost 5 years
    It would, but I believe the code speaks for itself in this case (considering comments are included and function names are pretty self explainitory)
  • A.s.ALI
    A.s.ALI almost 5 years
    It is now working for section headers, do you why?
  • Suhas Arvind Patil
    Suhas Arvind Patil over 4 years
    can we make the height fix for the side swipe buttons? eg: my cell is 150 and i want button to be show only 50.0f is it possible?
  • Maulik shah
    Maulik shah over 3 years
    do you have example
  • mojuba
    mojuba over 3 years
    Also setting the background color is not necessary. For destructive actions use the .destructive style, for others it can be .normal, in this case some system defaults will be used. In fact the destructive one is not exactly pure .red, it's something else.
  • ekashking
    ekashking almost 3 years
    How to trigger delete automatically once I swipe to the right???
  • Nikodem
    Nikodem almost 3 years
    You should use - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexP‌​ath *)indexPath. For UIContextualAction action please look at: stackoverflow.com/questions/5560602/…
  • ekashking
    ekashking almost 3 years
    That's what your example is already. And your reference has nothing related to my question: How to trigger delete action at the end of the swipe process (without clicking on a button)
  • Nikodem
    Nikodem almost 3 years
    I understand. Please look here: developer.apple.com/documentation/uikit/…
  • ekashking
    ekashking almost 3 years
    I'll rephrase. How to trigger delete or any action like WhatsApp swipe to reply to message by swiping just 1/3 of the screen and trigger action?
  • Nikodem
    Nikodem almost 3 years
    Sorry, but I can’t understand what do you mean. Please ask the question with attachment which will show your issue and paste here the link.