Reputation: 1183
Hola guys. I'm experiencing a little problem with touch handling and UIResponder.
My goal is to manage a single touch (moved) to interact with different views.
I added a gesture recognizer to my UIImageView that send a simple message to my customViewController. It allocate and display a custom view (subclassing a UIButton) over the tapped UIImageView.
I would be able (without have to release the initial finger tap) to send touch movement to my new allocated custom button.
It seems that my UIImageView swallow my touch and so my new Button can't feel the finger movement. I tried to resign first responder but it seems having no effect.
My custom Button work pretty good but only if I release the first tap and then tap again over the new displayer button.
Any suggests? Thank you in advance.
Some code here:
Inside my viewController I attached a longPressGestureRecognizer to my profileImageView that draw a circular button surrounding the profileImageView.
-(void)showMenu:(UIGestureRecognizer*)gesture {
[profileImageView removeGestureRecognizer:gesture];
[profileImageView setUserInteractionEnabled:NO];
ConcentricRadius radius;
radius.externalRadius = 75;
radius.internalRadius = 45;
GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:@"radio.png"] highlightedImage:[UIImage imageNamed:@"radio_selected.png"] radius:radius] autorelease];
[circularMenu setTag:kCircularTagControllerCircularMenu];
[circularMenu setCenter:[profileImageView center]];
// Buttons' frames will be set up by the circularMenu
UIButton *button1 = [[[UIButton alloc] init] autorelease];
UIButton *button2 = [[[UIButton alloc] init] autorelease];
UIButton *button3 = [[[UIButton alloc] init] autorelease];
UIButton *button4 = [[[UIButton alloc] init] autorelease];
[circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];
//[[self view] addSubview:circularMenu];
[[self view] insertSubview:circularMenu belowSubview:profileImageView];
}
Now I handle manually the touchEvent inside the circularMenu using the touchMoved methods.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
for (UIView *aSubview in _roundButtons) {
if ([aSubview isKindOfClass:[UIButton class]]) {
UIButton *aButton = (UIButton*)aSubview;
CGPoint buttonTouchPointConverted = [aButton convertPoint:touchLocation toView:aButton];
if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
[self rotateHighlightImage:aButton];
}
}
}
}
The goal is always to handle the end of gestureRecognizer and pass the touch event to the new instance created without having to lift my finger from the screen.
Any ideas?
PD: I handle touch manually with touchMoved cause if I use the addTarget:action:forControlEvents: on my buttons (1,2,3, and 4) the button that detect touchEvent swallow it and make other buttons impossible to feel the touch moving over them.
Upvotes: 0
Views: 1975
Reputation: 1183
Ok guys finally I solved my problem and I reached my goal!!
I discovered what was the real problem. Simply the GestureRecognizer handle touch Event until it's state is setted to UIGestureRecognizerStateEnded and for this reason the GestureRecognizer swallow touch events with no opportunity to send touch events to the rest of responder chain.
I read again the UIGestureRecognizer class reference and I found the property enabled.
To solve my problem the first thing I do when the gesture launch the target method is to set the gesture enabled to NO. In this way the gesture release immediately the touch control and the touchMoved can be executed.
Hope this help someone.
Above the modified code:
-(void)showMenu:(UIGestureRecognizer*)gesture {
[gesture setEnabled:NO]; // This is the key line of my problem!!
[profileImageView removeGestureRecognizer:gesture];
[profileImageView setUserInteractionEnabled:NO];
ConcentricRadius radius;
radius.externalRadius = 75;
radius.internalRadius = 45;
GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:@"radio.png"] highlightedImage:[UIImage imageNamed:@"radio_selected.png"] radius:radius] autorelease];
[circularMenu setTag:kCircularTagControllerCircularMenu];
[circularMenu setCenter:[profileImageView center]];
// Buttons' frames will be set up by the circularMenu
UIButton *button1 = [[[UIButton alloc] init] autorelease];
UIButton *button2 = [[[UIButton alloc] init] autorelease];
UIButton *button3 = [[[UIButton alloc] init] autorelease];
UIButton *button4 = [[[UIButton alloc] init] autorelease];
[circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];
//[[self view] addSubview:circularMenu];
[[self view] insertSubview:circularMenu belowSubview:profileImageView];
}
Upvotes: 1
Reputation: 44633
Your touchesEnded:withEvent:
will have to be the same as your touchesMoved:withEvent:
except it must invoke the method which is probably tied to the control event Touch Up Inside
event.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
for (UIView *aSubview in _roundButtons) {
if ([aSubview isKindOfClass:[UIButton class]]) {
UIButton *aButton = (UIButton*)aSubview;
CGPoint buttonTouchPointConverted = [aButton convertPoint:touchLocation toView:aButton];
if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
[aButton sendActionsForControlEvents:UIControlEventTouchUpInside];
return;
}
}
}
}
The only change I have made is to have the button send that control event for us.
Original Answer
In the function that handles your gesture, do this,
if ( gesture.state == UIGestureRecognizerStateEnded ) {
CGPoint point = [gesture locationInView:button];
if ( CGRectContainsPoint(button.bounds, point) ) {
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
This checks whether the last touch of the gesture was inside the button and sends a touch up inside event to all its targets.
Upvotes: 1
Reputation: 5611
I think you should change a setting on the view, once you create the button. Eg.
myImageView.userInteractionEnabled = NO;
This way, the UIImageView
will not listen to the touches any more.
Let me know if it works.
Upvotes: 0