quantum
quantum

Reputation: 1420

Forward UITouch event from superview to a UIControl subclass

I'm writing a radial menu, where when you long press (UILongPressGestureRecognizer) on the screen, it pops out a menu of buttons, and I can drag my finger (which is already touching the screen) over one of the buttons, which selects, then when I let go, it performs an action specific to that button.

I currently have the radial menu as a UIControl subclass, and I'm trying to override beginTrackingWithTouch: and continueTrackingWithTouch:, but the long press that shows the menu (adds it to the superview), does not get transferred to a touch recognized by the UIControl.

Any ideas how I can "forward" this touch event from the UIControl's superview to it?

Thanks!

Upvotes: 0

Views: 516

Answers (3)

clstroud
clstroud

Reputation: 143

I'm not sure if this is the same behavior you're looking for, but I recently had to overcome the exact same issue when developing my Concentric Radial Menu. The thing I discovered very quickly was that views added to the view hierarchy during the touch event do not get re-hit-tested and therefore seem unresponsive until the next event comes around.

The solution I used, which I can't say I love, was to implement a custom UIWindow subclass that intercepts - (void)sendEvent:(UIEvent *)event and forwards those events to the "active" radial menu.

That is, the menu registers with the window upon activation, then unregisters when being unloaded. If done atomically, this is actually a pretty safe technique, I just wish it were cleaner than it is.

Best of luck!

Upvotes: 0

DenisStad
DenisStad

Reputation: 27

I would do this...

The long press handler:

-(IBAction)onLongPress:(UILongPressGestureRecognizer*)recognizer
{
  CGPoint point = [recognizer locationInView:self.view];
  if (recognizer.state == UIGestureRecognizerStateBegan) {
    //create the radial view and add it to the view

    CGSize radialViewSize = CGSizeMake(80, 80);
    radialView = [[RadialView alloc] initWithFrame:CGRectMake(point.x - radialViewSize.width/2, point.y - radialViewSize.height/2, radialViewSize.width, radialViewSize.height)];

    [self.view addSubview:radialView];

    radialView.backgroundColor = [UIColor redColor];

  } else if (recognizer.state == UIGestureRecognizerStateEnded) {
    [radialView onTouchUp:[radialView convertPoint:point fromView:self.view]];
    [radialView removeFromSuperview];
    radialView = nil;
  }
}

In your radial view: (I suppose that the radial view keeps the buttons in an array)

-(void)onTouchUp:(CGPoint)point
{
  for (UIButton *button in buttons) {
    if ([button pointInside:[self convertPoint:point toView:button] withEvent:nil]) {
      //This button got clicked
      //send button clicked event
      [button sendActionsForControlEvents:UIControlEventTouchUpInside];
    }
  }
}

I know it's not perfect, since the touch events don't get forwarded to the radial view (as you asked), but it let's you click the buttons. Hope it helps!

Upvotes: 1

Joride
Joride

Reputation: 3763

Not a direct answer, but you should really watch the WWDC session about scrollviews of this year. And then watch it again. It contains a fantastic amount of information, and most certainly an answer to your question. It is session 235: advanced scrollviews and touch handling techniques.

Upvotes: 1

Related Questions