4

Disclaimer: I know it's not a best practice to tweak that kind of stuff because it may break as Apple decides to change its internal behaviour.

There are some solutions out there like https://stackoverflow.com/a/12511432/271150 which seem to be working for previous iOS versions, but not for iOS 7.

When looking into the controls hierarchy I can see there is a UITableViewCellDeleteConfirmationView inside the UITableViewCellScrollView. But by looking into the SubViews collection in layoutSubviews or willTransitionToState there are only my own views, UITableViewCellDeleteConfirmationView does not appear.

enter image description here

So, has anyone figured out how to modify the default delete button/view?

Community
  • 1
  • 1
asp_net
  • 3,567
  • 3
  • 31
  • 58
  • Possible duplicate: http://stackoverflow.com/questions/17254402/swipe-to-delete-and-the-more-button-like-in-mail-app-on-ios-7 – Krumelur Oct 09 '13 at 20:25
  • Nope. And it's not answered correctly either. – asp_net Oct 09 '13 at 20:27
  • There is no correct answer to "how to tweak a UI hierarchy you're not supposed to tweak" - it'll always be a hack. The 2nd and 3rd answer seems quite like a valid approach. – Krumelur Oct 09 '13 at 20:28
  • The question really is: do you want a DELETE button? Then keep the default behavior. Do you want something else? Then implement your own UITableViewCell and add a gesture recognizer to hide/show YOUR buttons. – Krumelur Oct 09 '13 at 20:38
  • I use a red tintColor in my app that seriously conflicts with the orange-red used by the delete button's background color, it would be really ideal to set it to the same UIColor as my tintColor, I think adding my own gesture recognizer for that is a bit overkill. Be nice if we could modify it directly for edge cases like that, it's a good question. – Billy Gray Dec 31 '13 at 19:18

3 Answers3

4

I understand you may not want to overwrite Apples entire implementation for editing a table view cell BUT I had a similar problem with my app. In my case I needed two buttons (More and Lost) to display just like in the new reminders app for iOS7 when a user swipes left to right. Instead of using:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

I created a custom cell that hides the buttons under the top layer and uses a pan gesture recogniser to move the top layer, displaying the buttons underneath. I therefore have complete control over what buttons are displayed and what color etc they are (see below).

static CGFloat const kEditButtonWidth = 82.0;

@interface MyCustomCell ()
@property (nonatomic, assign) CGFloat firstX;
@property (nonatomic, assign) CGFloat firstY;
@property (nonatomic, strong) UIView *topLayer;
@property (nonatomic, strong) UIButton *moreButton;
@property (nonatomic, strong) UIButton *lostButton;
@property (nonatomic, strong) UILabel *titleLabel;
@end

@implementation MyCustomCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self) {

        // BOTTOM LAYER (MORE AND LOST BUTTONS)
        UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [aButton setFrame:CGRectZero];
        [aButton setTitle:@"More" forState:UIControlStateNormal];
        [aButton setTitleShadowColor:[UIColor clearColor] forState:UIControlStateNormal];
        [aButton setBackgroundColor:[UIColor colorWithRed:0.78 green:0.78 blue:0.78 alpha:1.0]];
        [[self contentView] addSubview:aButton];
        [self setMoreButton:aButton];

        aButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [aButton setFrame:CGRectZero];
        [aButton setTitle:@"Lost" forState:UIControlStateNormal];
        [aButton setTitleShadowColor:[UIColor clearColor] forState:UIControlStateNormal];
        [aButton setBackgroundColor:[UIColor colorWithRed:1.00f green:0.23f blue:0.19f alpha:1.00f]];
        [[self contentView] addSubview:aButton];
        [self setLostButton:aButton];

        // TOP LAYER
        UIView *aView = [[UIView alloc] initWithFrame:CGRectZero];
        [aView setBackgroundColor:[UIColor whiteColor]];
        [[self contentView] addSubview:aView];
        [self setTopLayer:aView];

        UIPanGestureRecognizer *aPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAction:)];
        [aPanRecognizer setMinimumNumberOfTouches:1];
        [aPanRecognizer setMaximumNumberOfTouches:1];
        [aView addGestureRecognizer:aPanRecognizer];

        // title label
        UILabel *aLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [aView addSubview:aLabel];
        [self setTitleLabel:aLabel];
    }
    return self;
}

- (void)layoutSubviews {

    [super layoutSubviews];

    CGRect bounds = [[self contentView] bounds];
    CGRect frame = CGRectZero;

    // BOTTOM LAYER (MORE AND LOST BUTTONS)
    frame.origin.x = bounds.size.width-(kEditButtonWidth+kEditButtonWidth); // two buttons wide
    frame.size.width = kEditButtonWidth;
    frame.size.height = bounds.size.height;
    [[self moreButton] setFrame:frame];

    frame.origin.x += kEditButtonWidth;
    [[self lostButton] setFrame:frame];

    // TOP LAYER
    frame = bounds;
    CGPoint anchorPoint = CGPointMake(0.0f, [[[self topLayer] layer] anchorPoint].y);
    [[[self topLayer] layer] setAnchorPoint:anchorPoint];
    [[self topLayer] setFrame:frame];

    // title label
    frame.origin.x = 20.0;
    frame.origin.y = 4.0;
    frame.size.width = bounds.size.width-40.0;
    frame.size.height = 21.0;
    [[self titleLabel] setFrame:frame];
}

- (void)panGestureAction:(id)sender {

    // on the first touch, get the center coordinates (x and y) of the view
    CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self];
    if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
        [self setFirstX:[[sender view] center].x];
        [self setFirstY:[[sender view] center].y];
    }

    // add translated point to reference points
    translatedPoint = CGPointMake([self firstX]+translatedPoint.x, [self firstY]);
    [[sender view] setCenter:translatedPoint];

    // when pan ends (set final x to be either back to zero or showing buttons)
    if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
        CGFloat finalX = translatedPoint.x+(0.30*[(UIPanGestureRecognizer*)sender velocityInView:self].x);
        if (finalX < -1.0f*FMEditButtonWidth) {
            finalX = -2.0f*FMEditButtonWidth;
            [self setEditMode:YES];
        } else {
            finalX = 0.0f;
            [self setEditMode:NO];
        }

        // animate view
        [UIView animateWithDuration:1.0 delay:0.0 usingSpringWithDamping:1.0f initialSpringVelocity:1.0f options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState animations:^{
            [[sender view] setCenter:CGPointMake(finalX, [self firstY])];
        } completion:NULL];
    }
}

@end

Hope this helps.

pheedsta
  • 2,058
  • 2
  • 16
  • 11
  • Thanks for sharing! I will give it a try in the next weeks. – asp_net Oct 17 '13 at 10:39
  • i tried the code, but i can not figure out, why the gesture is not recognized. the method does not get called. can you help here? – alexdd55 Dec 26 '13 at 18:37
  • @alexdd55 set a break-point in initWithStyle: to see that it's firing and hooking up your gesture correctly. – Billy Gray Dec 31 '13 at 19:20
  • how do you detect when to hide the more and lost buttons? I cant figure out how to make it so you can only slide one cell at a time. – AlBeebe Feb 03 '14 at 19:15
0

The reason you don't see the view inside layoutSubviews or willTransitionToState: is that the delete button view does not exist yet or it is not part of the view hierarchy yet. In order to "see" it you need to postpone a little the code that browses the view hierarchy, and by that allowing the OS to create/add the view in the meantime:

- (void)willTransitionToState:(UITableViewCellStateMask)state
{
    [super willTransitionToState:state];

    if (state & UITableViewCellStateShowingDeleteConfirmationMask)
    {
        [self performSelector:@selector(findDeleteButtonViewThroughViewHierarchy:) withObject:self.subviews afterDelay:0];
    }
}

Note this is a fragile solution since it is based on internal implementation of Apple that might change any time.

See here an (almost) complete example:

Customizing iOS 7 Delete button

Community
  • 1
  • 1
HyBRiD
  • 688
  • 4
  • 23
-1

Not sure if this works on ios 7 but take a look:

(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{

  if (editingStyle == UITableViewCellEditingStyleDelete)

   {

    //   Your Code

    }
}