I have an MPMoviePlayerController which I add to a view with:
MPMoviePlayerController *mpc = INIT and other stuff
[self.view addSubview:mpc.view];
In IB I've hooked up a tap gesture recognizer to a selector called showhide:.
I have a toolbar on the screen, and when it's touched it prevents the gesture from going through with:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
CGPoint touchedPoint = [touch locationInView:self.view];
if (self.controlsVisable) {
BOOL inbar = CGRectContainsPoint(self.controlBar.frame, touchedPoint);
NSLog(#"inbar? %d", inbar);
return !inbar;
}
return YES;
}
And that works perfectly. If I tap in the bar, it prints "inbar? 1" and otherwise it prints "inbar? 0". So clearly it is getting the touches. But it never executes showhide:.
To clarify, showhide: should fire only when I press outside of the bar. Also, regardless of if I tap inside or outside of the bar, showhide: never fires
Related
I have a container view which has two UILongPressGestureRecognizers on it (well not only those two, but other gestures are acting ok). One is to recognize one finger, the other is for two. When i try to fire gesture for one finger, it will not fire it's target method until finger is lift off. The second one for two fingers is working as expected, firing selector action after short period of time. When i disable gesture for two finger press, the one finger press gets back to normal. How gestures are initialized, first is one finger gesture, initialized inside vc setup.
- (void) setupGestures
{
[self.contentView addGestureRecognizer:self.longGestureRecognizer];
}
- (UILongPressGestureRecognizer *)longGestureRecognizer
{
if (!_longGestureRecognizer) {
_longGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressAction:)];
[_longGestureRecognizer setMinimumPressDuration:1];
}
return _longGestureRecognizer;
}
The second one is initalized a bit later, but not from host VC, but inside view which is added to it
//Called in host
rullerView = [[RullerView alloc] initWithContent:self.contentView viewController:self];
and in init of view:
//This is called from within previous call initWithContent:ciewController:
- (void)setupGestures
{
UILongPressGestureRecognizer *rullerGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(rullerTapAction:)];
[rullerGestureRecognizer setNumberOfTouchesRequired:2];
//view here is a content view passed into init, basically the same one
//to which first recognizer is added, however selector action is contained
//in this view, and this view is target for this recognizer
[view addGestureRecognizer:rullerGestureRecognizer];
}
Could this be a problem?? Already tried
[gesture requireGestureRecognizerToFail:otherGesture];
and delegate method of view which recognizers are added to:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
This is what I want to do
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view != self.myView) {
NSLog(#"we went with no");
//don't let anything that's not myView fire the gesture recognizer
return NO;
}
NSLog(#"we went with yes");
return YES;
}
The problem is the code always chooses the path of "we went with no" no matter where I actually tap. How do I fix my if check?
If you're finding that your gesture recognizer action is firing when you're tapping outside of a specific view, you should double-check that you added the gesture recognizer correctly.
[self.myView addGestureRecognizer:[[UIGestureRecognizer alloc] initWithTarget:self action:#selector(someAction:)]];
If you still experience incorrect action fires, you could check the touch location.
if (CGRectContainsPoint(self.myView.bounds, [gesture locationInView:self.myView]))
I am trying to handle tableViewCell's being tapped, but the problem is that this is a "temporary tableView". I have it coded so that it will appear while the user is editing a UITextField, but then I set up a gesture recognizer to set the tableview to hidden as soon as the user clicks somewhere away from the UITextField.
I have the gesture recognizer set up as follows:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[tap setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:tap];
However, dismissKeyboard is called before didSelectRowAtIndexPath is called, and so the TableView that I want to handle the event on becomes hidden and therefore this function is never called.
My question is: Does anybody have ideas of how to get around this, so that didSelectRowAtIndexPath will execute before the tableView hides? I had one idea to somehow see if the tableView is where the tap is coming from, and if so, then don't execute the "hide tableView" line within dismissKeyboard. Is this possible?
Sorry, but I am new to iOS dev, so thank you for any advice!
You should be able to do this by making your view controller the tap gesture's delegate and denying it any touches that are inside the table view. Here is a starting point:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
{
//Assuming your table view is a direct subview of the gesture recognizer's view
BOOL isInsideTableView = CGRectContainsPoint(tableView.frame, [touch locationInView:gesture.view])
if (isInsideTableView)
return NO;
return YES;
}
Hope this helps!
You could set yourself as a delegate to the UITapGestureRecognizer and cancel the gesture when the user taps within the tableView.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//You can also (and should) check to make sure the gestureRecognizer is the tapGestureRecognizer
if (touch.view == tableView)
{
return NO;
}
else
{
return YES;
}
}
To better fit what you need, judge if your search bar is first responder.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
{
BOOL isInsideTableView = CGRectContainsPoint(yourTabelView.frame, [touch locationInView:gesture.view]);
if (isInsideTableView && ![yourSearchBar isFirstResponder])
return NO;
return YES;
}
On my mapview I draw polygon overlays that belong to a specific annotation. I want that annotation to be selected when the overlay is tapped. My first attempt was to add a UITapGestureRecognizer to the mapview, test whether the tapped point is inside a polygon and perform [mapView selectAnnotation:myAnnotation] on success. The problem is that after this, the mapview decides there was a tap not on any annotations, so it deselects the annotation again.
My question is how to best prevent this from happening, I don't seem to be able to find a nice solution. What I have tried:
Create a new UIGestureRecognizer subclass that recognizes just taps inside overlays, then iterate through mapView.gestureRecognizers and call requireGestureRecognizerToFail on each. However, the mapview does not expose any recognizers through its property.
Return YES for shouldBeRequiredToFailByGestureRecognizer in my custom recognizer for any other recognizer that isKindOfClass tap recognizer. However, there still seems to be another recognizer that is not passed in there.
Place a transparent view on there and do the polygon check in pointInside:withEvent, but does also blocks any other gestures besides only taps.
EDIT:
After poking around a bit more, I have code that is almost working, of which I know where it goes wrong. I have a custom recognizer as before. In its delegate I do:
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
[otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer]; // can possibly do this in custom recognizer itself instead
return YES;
}
Now taps inside polygons successfully prevent deselection. However, when I then do:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView
{
// displayRegion is chosen to center annotation
[mapView setRegion:self.displayRegion animated:YES];
}
it breaks again, and the annotation gets deselected again..
It seems we have the same problem ( a little different: i'm tryng to select manually an annotation in a gesture recognizer )
I'm doing so ( and it works, but it seems to complex to me , feel free to ask more if it's not clear ):
i'm working with a long pressure event :
...
_lp1 = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleOverlayLp1:)];
((UILongPressGestureRecognizer*)_lp1).minimumPressDuration = 0.05;
_lp1.delegate = self;
[_mapView addGestureRecognizer:_lp1];
...
I collect all gesture recognizers in a global var :
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (_gestureRecognizers==nil)
_gestureRecognizers = [NSMutableSet set];
[_gestureRecognizers addObject:otherGestureRecognizer];
return YES;
}
// when i recognize gestures, disable everything and call an asyncrhronous task where i re-enable
- (void)handleOverlayLp1:(UIGestureRecognizer*)recognizer
{
// Do Your thing.
if (recognizer.state == UIGestureRecognizerStateBegan)
{
BOOL found=NO;
...
if (found) {
// disable gestures, this forces them to fail, and then reenable in selectOverlayAnnotation that is called asynchronously
for (UIGestureRecognizer *otherRecognizer in _gestureRecognizers) {
otherRecognizer.enabled = NO;
[self performSelector:#selector(selectOverlayAnnotation:) withObject:polyline afterDelay:0.1];
}
}
}
}
- (void)selectOverlayAnnotation: (id<MKAnnotation>) polyline
{
[_mapView selectAnnotation:polyline animated:NO];
for (UIGestureRecognizer *otherRecognizer in _gestureRecognizers) {
otherRecognizer.enabled = YES;
}
}
I've created a mini pop-up menu for the iPhone in a UIView, and I'd like the user to be able to dismiss the view if they do anything other than select one of the options. So, if a user taps/swipes/pinches any other element on the screen, the pop-up view should disappear.
However, I don't want to detect a gesture that will stop something else from happening... For example, there is a UITableView underneath and if I swipe up or down on it, I want it to move as expected as well as dismissing the mini pop-up view.
Should I use multiple gesture recognizers, or should I use touchesBegan, or is there a better way of doing it?
Put this in your UIViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch.view!=yourView && yourView) {
[yourView removeFromSuperview];
yourView=nil;
}
}
EDIT: changes made to detect touch and remove only if view exists
EDIT2: Well you could add the following to your UIButtons/UITableView methods
if (yourView) {
[yourView removeFromSuperview];
yourView=nil;
}
or add touchesBegan:withEvent: as a touchDown event to your buttons.
Both annoying to do but can't see another way to do it as the touchesBegan method doesn't get called with interactive elements.
EDIT3: Right scrap that, think i've nailed it
in your interface add the UIGestureRecognizerDelegate
#interface ViewController : UIViewController <UIGestureRecognizerDelegate> {
then in your viewDidLoad add this
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapMethod)];
tapped.delegate=self;
tapped.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapped];
then in your viewController add these 2 methods
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (touch.view!=yourView && yourView) {
return YES;
}
return NO;
}
-(void)tapMethod {
[yourView removeFromSuperview];
yourView=nil;
}