Search code examples
iphoneuiviewtouchesbegantouchesmoved

need UIButton inside custom UIView respond to touches


I have a custom UIView with some buttons as subviews. I am using touchesBegan/Moved/Ended to rotate the view with the user's finger. The problem is, when I try to drag/rotate the view from a button, the touches methods aren't called. I need the buttons to respond to the UIControlEventTouchUpInside event, but if it is dragged with the view, then to make my view rotate. I have looked at this question and this question, but couldn't get either solution to work for me.

Here is my custom view code:

- (id)initWithFrame:(CGRect)frame andRadius:(float)Radius andViews:

(NSMutableArray *)AllViews
{
    self = [super initWithFrame:frame];
    if (self) {
        radius = Radius;
        allViews = AllViews;

        for(int i = 0; i < [allViews count]; i++){
            //the "currentView" is a UIButton
            UIView *currentView = (UIView *)[allViews objectAtIndex:i];
            [currentView setFrame:CGRectMake(frame.size.width / 2 - 25 + radius * cos((2 * M_PI / [allViews count]) * i), frame.size.height / 2 - 25 + radius * sin((2 * M_PI / [allViews count]) * i), 50, 50)];
            [self addSubview:currentView];

        }
        [self setBackgroundColor:[UIColor redColor]];
        [self setAlpha:.5];

    }
    return self;
}

//- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
//{
//    for (UIView * view in [self subviews]) {
//        if ([view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
//            return YES;
//        }
//    }
//    return NO;
//}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];

    x = point.x;
    y = point.y;

    NSLog(@"touchesBegan");
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];

    float X = point.x;
    float Y = point.y;

    float a = sqrt(X * X + Y * Y);
    float b = sqrt(x * x + y * y);
    float c = sqrt((x - X) * (x - X) + (y - Y) * (y - Y));

    float alpha = acos((a * a + b * b - (c * c)) / (2 * a * b));
    if(alpha == NAN)
        alpha = 0;

    alpha = -alpha;


    [UIView beginAnimations:@"rotate" context:nil];
    [UIView setAnimationDuration:0];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    self.transform = CGAffineTransformRotate(self.transform, alpha);
    [UIView commitAnimations];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];

    float X = point.x;
    float Y = point.y;

    float a = sqrt(X * X + Y * Y);
    float b = sqrt(x * x + y * y);
    float c = sqrt((x - X) * (x - X) + (y - Y) * (y - Y));

    float alpha = acos((a * a + b * b - (c * c)) / (2 * a * b));

    alpha = -alpha;


    [UIView beginAnimations:@"rotate" context:nil];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    self.transform = CGAffineTransformRotate(self.transform, alpha);
    [UIView commitAnimations];
    NSLog(@"touchesEnded");
}

- (void)dealloc
{
    [allViews release];
    [super dealloc];
}

Any suggestions?


Solution

  • Just incase someone comes across a similar issue, I'll post the solution I used. I overrode another UIView class that I used as a button. In each of the touchedBegan/Moved/Ended, I implemented the code I need for the button click, then passed the touch up the chain of command to the next custom UIView, like so:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [self.nextResponder touchesBegan:touches withEvent:event];
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [self.nextResponder touchesMoved:touches withEvent:event];
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView:self];
    
        if (point.x < self.frame.size.width && point.y < self.frame.size.height) {
            NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:[NSString stringWithFormat:@"%d", self.tag], @"tag", nil];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"ChangeFilter" object:self userInfo:userInfo];
        }
    
    
        [self.nextResponder touchesEnded:touches withEvent:event];
    }
    

    Notice that I use NSNotifications to send the action to my ViewController that contains the overridden view.