38

I wanted to change the color of minus button and delete button of UITableViewCell when click on edit button or swiping UITableView rows. I have implemented this code so far :

-(IBAction)doEdit:(id)sender
{

    [[self keyWordsTable] setEditing:YES animated:NO];
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {

}
Unheilig
  • 15,690
  • 193
  • 65
  • 96
Hussain Shabbir
  • 13,963
  • 4
  • 34
  • 53
  • check this: http://stackoverflow.com/questions/1615469/custom-delete-button-on-editing-in-uitableview-cell – Ilario Nov 29 '13 at 17:28
  • 3
    Seems like you never got an answer on how to change the color of the actual minus button, just the confirmation delete button. – SAHM Mar 16 '17 at 00:52

5 Answers5

101

iOS 8 and 9 (props to this post)


Note: If you are working with an existing iOS 7 project, you'll need to update the target to iOS 8 to get this functionality. Also remember to set the UITableviewDelegate.

All the magic now happens here (as many buttons as you want too!!!!):

 -(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
 UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
    {
        NSLog(@"Action to perform with Button 1");
    }];
    button.backgroundColor = [UIColor greenColor]; //arbitrary color
    UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
                                    {
                                        NSLog(@"Action to perform with Button2!");
                                    }];
    button2.backgroundColor = [UIColor blueColor]; //arbitrary color

    return @[button, button2];
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:

}
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES;
    }


(iOS 7)


**activate the delete button on swipe**

// make sure you have the following methods in the uitableviewcontroller

    - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES;
    }
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"You hit the delete button.");
    }

set custom text label instead of delete.

-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return @"Your Label";
}

set custom color for button part 1 - warning, this technically involves poking at the private apple API. However, you are not prevented from modifying a subview using a public method search that is part of UIKIT.

Create a uitableviewcell class (see also https://stackoverflow.com/a/22350817/1758337 )

- (void)layoutSubviews
{
    [super layoutSubviews];
    for (UIView *subview in self.subviews) {
        //iterate through subviews until you find the right one...
        for(UIView *subview2 in subview.subviews){
            if ([NSStringFromClass([subview2 class]) isEqualToString:@"UITableViewCellDeleteConfirmationView"]) {
                //your color
                ((UIView*)[subview2.subviews firstObject]).backgroundColor=[UIColor blueColor];
            }
        }
    }    
}

Another note: there's no guarantee this approach will work in future updates. Also beware that mentioning or using the private UITableViewCellDeleteConfirmationView class may lead to AppStore rejection.

set custom color for button part 2

back in your uitableviewcontroller

- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    [YourTableView reloadData];
}

(The alternate color won't be called until the next time layoutSubviews is called on the tablecell, so we ensure this happens by reloading everything.)

Community
  • 1
  • 1
timothykc
  • 2,225
  • 1
  • 14
  • 14
  • Will this work with iOS 7.2? 7.3? 8.0b1? 8.0b3? Also, using `UITableViewCellDeleteConfirmationView` in your code is a sure way to have your app rejected. – Leo Natan Mar 14 '14 at 15:07
  • The only change from 6 to 7 was the naming convention--from UITableViewCellDeleteConfirmationControl to UITableViewCellDeleteConfirmationView. I'm not doing anything other than finding the view and then changing its background. Plenty of apps have used this technique prior. If Apple says no, it's not a big worry for me. The rest of the techniques are kosher and in the documentation :). Anyways, I've tried other solutions such as SWTableCells, but found the precision lacking compared to the baked in apple button. I just don't want a red button because of the apps color scheme. – timothykc Mar 14 '14 at 15:44
  • You should at least attempt to hide the use of private API. Also, the private view hierarchy between iOS6 and iOS7 table view cells has changed significantly. Your subview traversal, while working for now, may or may not break with every future release. But the worst in your post is the blatant use of private API. – Leo Natan Mar 14 '14 at 16:24
  • 1
    Thanks for the feedback and warnings. They are appreciated even though I'm going to throw caution the wind anyways. I'm going to edit the answer so that anyone else treading down understands that it's caveat emptor. Regarding if it breaks down the road, the only real loss is color, and if I have to code a custom solution then, so be it :) – timothykc Mar 14 '14 at 21:41
  • The code works in ios7 but not in ios8. The call to 'reloadData' freezes the cell. What I do is to force layout adjustment for the dell here:`-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* myCell = [tableView cellForRowAtIndexPath:indexPath]; [myCell setNeedsLayout]; return m_sMyTitle; }` – FrizzTheSnail Sep 26 '14 at 10:24
  • Thanks for the heads up. I'm going to update my answer with what will be the de-facto method in iOS 8 and beyond. – timothykc Sep 26 '14 at 16:41
  • The way to avoid app store rejection based on string matching is to invert the test logic, e.g., test against all possible valid public classes and your classes. Here's a Swift extension on `NSObject` for iOS 8.3: https://gist.github.com/8e7865f3be439e3b15d7 –  Jun 04 '15 at 05:09
  • 1
    Note, you no longer need to implement `commitEditingStyle` , the `UITableViewRowAction`'s handler is called instead – Ashley Mills Jul 21 '16 at 12:18
  • The method is not being called... everything is configured correctly... I can delete, reorder rows, etc. but `editActionsForRowAtIndexPath` isn't called! iOS 11.3 any ideas? – Ixx May 23 '18 at 20:10
23

Swift Example (iOS 8)

UITableViewDelegate docs (editActionsForRowAtIndexPath method)

Return Value

An array of UITableViewRowAction objects representing the actions for the row. Each action you provide is used to create a button that the user can tap.

Discussion

Use this method when you want to provide custom actions for one of your table rows. When the user swipes horizontally in a row, the table view moves the row content aside to reveal your actions. Tapping one of the action buttons executes the handler block stored with the action object.

If you do not implement this method, the table view displays the standard accessory buttons when the user swipes the row.

Working example in Swift:

@available(iOS 8.0, *)
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let button1 = UITableViewRowAction(style: .Default, title: "Happy!") { action, indexPath in
        print("button1 pressed!")
    }
    button1.backgroundColor = UIColor.blueColor()
    let button2 = UITableViewRowAction(style: .Default, title: "Exuberant!") { action, indexPath in
        print("button2 pressed!")
    }
    button2.backgroundColor = UIColor.redColor()
    return [button1, button2]
}

func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
}
Community
  • 1
  • 1
clearlight
  • 10,772
  • 11
  • 48
  • 65
3

fist time you call willTransitionToState in .m (customcell)

- (void)willTransitionToState:(UITableViewCellStateMask)state{
    NSLog(@"EventTableCell willTransitionToState");
    [super willTransitionToState:state];
    [self overrideConfirmationButtonColor];
}

Check version iOS, it's here, i'm using iOS 7 - iOS8

//at least iOS 8 code here
- (UIView*)recursivelyFindConfirmationButtonInView:(UIView*)view
{
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {
        // iOS 8+ code here
        for(UIView *subview in view.subviews) {

            if([NSStringFromClass([subview class]) rangeOfString:@"UITableViewCellActionButton"].location != NSNotFound)
                return subview;

            UIView *recursiveResult = [self recursivelyFindConfirmationButtonInView:subview];
            if(recursiveResult)
                return recursiveResult;
        }
    }

    else{
        // Pre iOS 8 code here
        for(UIView *subview in view.subviews) {
            if([NSStringFromClass([subview class]) isEqualToString:@"UITableViewCellDeleteConfirmationButton"]) return subview;
            UIView *recursiveResult = [self recursivelyFindConfirmationButtonInView:subview];
            if(recursiveResult) return recursiveResult;
        }
    }
    return nil;


}

-(void)overrideConfirmationButtonColor
{

    dispatch_async(dispatch_get_main_queue(), ^{
        UIView *confirmationButton = [self recursivelyFindConfirmationButtonInView:self];
        if(confirmationButton)
        {
            UIColor *color = UIColorFromRGB(0xFF7373);
            confirmationButton.backgroundColor = color;

        }
    });
}
Giang
  • 1,576
  • 2
  • 19
  • 22
2

Not possible using public API.

For the delete button, you can use a custom implementation, such as SWTableViewCell, to change the color of the button, as well as add others.

Leo Natan
  • 55,734
  • 8
  • 140
  • 186
1

Old Question, but am sure there are some people who support iOS 7. To change the delete button background colour, you need to create "UITableViewCell" class or extend it. then you can use

- (void)layoutSubviews
{
    [super layoutSubviews];
    for (UIView *subview in self.subviews) {
        for(UIView *childView in subview.subviews){
            if ([childView isKindOfClass:[UIButton class]]) {
                childView.backgroundColor = [UIColor blueColor];
            }
        }
    }
}
Ofcourse
  • 488
  • 1
  • 6
  • 16