4

Currently I'm trying to customize delte button in UITableViewCell. Now I've got something like that:

enter image description here

Now, all what I need is to change the color of this button, I don't want to change the behavior, or to make it absolutelly custom. I'm sure that it is possible, without creating your own controls for deleting rows in UITableView.

This my code:

- (void)layoutSubviews
{
    [super layoutSubviews];

    for (UIView *subview in self.subviews) {
        if ([NSStringFromClass([subview class]) isEqualToString:@"UITableViewCellDeleteConfirmationControl"]) {
            UIView *deleteButtonView = (UIView *)[subview.subviews objectAtIndex:0];
            deleteButtonView.backgroundColor = [UIColor greenColor];
        }
    }
}

How could I do this?

Thanks in advance!

Anatoliy Gatt
  • 2,501
  • 3
  • 26
  • 42
  • I don't think this is possible without a custom UITableViewCell subclass. Why are you sure it's possible? – DrummerB Aug 26 '12 at 14:25
  • @DrummerB I read a lot about customization of this button, obviously my cell is custom, I'm already subclassing UITableViewCell, but I don't understand how to simply change the color, most of the time people want to change animation or whole view of this button. – Anatoliy Gatt Aug 26 '12 at 14:27
  • @DrummerB I don't want to change any behaviours, just color. – Anatoliy Gatt Aug 26 '12 at 14:29
  • I'm not aware of any (documented) way to access that button. The only way to customize it is by setting it's text. You could try to iterate through all the subview's of the cell and try to find the button (very bad and unflexible solution!) But even if you find it, UIButton doesn't have a tint property. You would have to create your tinted stretchable background image in the image editing software of your choice. – DrummerB Aug 26 '12 at 14:39

6 Answers6

5

UITableViewCellDeleteConfirmationControl is not a public class and you cannot easily change its appearance.

In order to do so I believe you'd have to iterate through the subviews of the cell and change its properties:

for (UIView *subview in self.subviews) {
    if ([NSStringFromClass([subview class]) isEqualToString:@"UITableViewCellDeleteConfirmationControl") {
        // Set the background using an image.
    }
}

Of course, you should be wary of doing this sort of thing since its rather fragile. I'd suggest rolling your own instead.

I'd suggest submitting a bug report to Apple to request the ability to edit this more easily.

tgt
  • 1,308
  • 1
  • 10
  • 16
  • But I don't see any results, even when I try to add subview such as button, it won't do it, but UILabel fits there perfectly. – Anatoliy Gatt Aug 26 '12 at 15:29
4

In the UITableViewCell subclass:

- (UIView*)recursivelyFindConfirmationButtonInView:(UIView*)view
{
    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) confirmationButton.backgroundColor = [UIColor orangeColor];
    });
}

Then in the UITableViewDelegate:

-(void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    <#Your cell class#> *cell = (<#Your cell class#>*)[self.tableView cellForRowAtIndexPath:indexPath];
    [cell overrideConfirmationButtonColor];
}

This works in iOS 7.1.2

silyevsk
  • 4,021
  • 3
  • 31
  • 30
2

Here's how to:

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,235
  • 1
  • 16
  • 14
2

silyevsk's example is excellent... but, six months later, iOS 8 has come along, and it doesn't quite work properly anymore.

Now, you need to look for a subview called "_UITableViewCellActionButton" and set the background color of that.

Below is a modified version of silyevsk's code which I've used in my app.

On some of my UITableView cells, I didn't want the user to be able to swipe-to-delete, but I did want something (a padlock icon) to appear when they swiped.

enter image description here

To do this, I added a bReadOnly variable to my UITableViewCell class

@interface NoteTableViewCell : UITableViewCell

. . . 

@property (nonatomic) bool bReadOnly;

-(void)overrideConfirmationButtonColor;

@end

and I added silyevsk's code to my .m file:

- (UIView*)recursivelyFindConfirmationButtonInView:(UIView*)view
{
    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;
    }
    return nil;
}

-(void)overrideConfirmationButtonColor
{
    if (!bReadOnly)
        return;

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

            UIImageView* imgPadLock = [[UIImageView alloc] initWithFrame:confirmationButton.frame];
            imgPadLock.image = [UIImage imageNamed:@"icnPadlockBlack.png"];
            imgPadLock.contentMode = UIViewContentModeCenter;     //  Don't stretch the UIImage in our UIImageView

            //  Add this new UIImageView in the UIView which contains our Delete button
            UIView* parent = [confirmationButton superview];
            [parent addSubview:imgPadLock];
        }
    });
}

Also, I needed to change the code which populates the UITableView, otherwise the "Delete" label would appear aswell as the padlock icon:

-(NSString*)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Note* note = [listOfNotes objectAtIndex:indexPath.row];
    if ( /* Is the user is allowed to delete this cell..? */ )
        return @"Delete";

    return @"      ";
}

It's still ugly, and relies on assumptions that this won't all change when iOS 9 comes along.

Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
1

This is the solution:

- (void)layoutSubviews
{
    [super layoutSubviews];

    for (UIView *subview in self.subviews) {
        if ([NSStringFromClass([subview class]) isEqualToString:@"UITableViewCellDeleteConfirmationControl"]) {
            UIView *deleteButtonView = (UIView *)[subview.subviews objectAtIndex:0];
            UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Background"]];
            [deleteButtonView addSubview:image];
        }
    }
}
Anatoliy Gatt
  • 2,501
  • 3
  • 26
  • 42
  • This approach needs to be modified for iOS 7. See my answer above, as well as http://stackoverflow.com/a/22350817/1758337 – timothykc Mar 15 '14 at 00:17
1

IOS7 compatible answer (not creating a custom class, but extending the UITableViewCell :

@implementation UITableViewCell (customdelete)
- (void)layoutSubviews
{
    [super layoutSubviews];
    for (UIView *subview in self.subviews) {
        for(UIView *subview2 in subview.subviews){
            if ([NSStringFromClass([subview2 class]) isEqualToString:@"UITableViewCellDeleteConfirmationView"]) {
                ((UIView*)[subview2.subviews firstObject]).backgroundColor=COLOR_RED;
//YOU FOUND THE VIEW, DO WHATEVER YOU WANT, I JUST RECOLOURED IT
            }
        }
    }
}
@end
Skrew
  • 1,768
  • 1
  • 16
  • 17
  • This approach works. You may need to add this to the UITableViewController in order for the custom color to show up however... - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath { [self.yourTableView reloadData]; } – timothykc Mar 14 '14 at 04:08