Search code examples
iosuicontrol

Custom UISwitch inside a UITableViewCell


I've implemented a really simple custom UISwitch that uses touches events like:

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event

I can use this control in my views without problem. The Control simulates a UISwitch, so it can change value through a drag or through a tap.

My problem is that I can't let this Control work inside a Cell of a UITableView. Only the single tap seems to work (note that I'm not using gesture... but the events that I've previously listed) but I can't "swipe" the switch handle.

I instantiate the controller within the tableView:cellForRowAtIndexPath method adding the control as subview of the cell contentView:

[cell.contentView addSubview:customSwitch];

I suppose that it is something related with the fact that UITableView is a UIScrollView and I think that touches events get somehow "stolen" by it.

// EDIT --------------------

Here is the code related with the Touch events.

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super beginTrackingWithTouch:touch withEvent:event];

    self.dragged = NO;

    return YES;
}

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    if (!self.enabled) {
        return NO;
    }

    [super continueTrackingWithTouch:touch withEvent:event];
    self.dragged = YES;
    CGPoint touchPoint = [touch locationInView:self];

    float centerPoint = FIXED_WIDTH / 2.0;

    [self centerOn:(touchPoint.x > centerPoint) animated:YES completion:nil];

    return YES;
}

- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
    [super endTrackingWithTouch:touch withEvent:event];

    CGPoint touchPoint = [touch locationInView:self];

    BOOL currentOn = self.on;
    BOOL nextOn;

    if (self.dragged) {
        float centerPoint = FIXED_WIDTH / 2.0;
        nextOn = (touchPoint.x > centerPoint);

        [self setOn:nextOn animated:NO];
    }else{
        nextOn = !self.on;
        [self setOn:nextOn animated:YES];
    }
    self.dragged = NO;

    if (currentOn != nextOn) {
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

How can I make the control work inside a Cell without interfering with the UIScrollView/UITableView?


Solution

  • You need to implement your custom switch using gestures instead of trying to directly process events.

    The gesture recognizers work behind the scenes to coordinate their event processing which, for example, is why a UIScrollView can work inside of another UIScrollView. You need that coordination for the UITableView (really a UIScrollView) to properly handle swipe gestures within its content.

    Search the web for Hardy Macia's UICustomSwitch sample code for a good example of matching the UISwitch behaviors in a custom control.