UIGestureRecognizer under the other UIView - ios

I couldn't find a solution for my small problem with Gestures and hierarchy. There you have how it is looks like:
-superview
--view A
---objectViewA z UIGestureRecognizer
--view B
---objectViewB z UIGestureRecognizer
On the beginning viewA and viewB are hidden. User unhide it as he wants. When the viewB is not covering viewA I can move objectViewA but if we will unhide viewB I can move objectViewB but objectViewA doesn't return any touch.
I added shouldRecognizeSimultaneouslyWith delegate but it doesn't work. It didn't get any action.
How to fix this problem? I will be glad!

You can use the UIGestureRecognizerDelegate to determine if viewB should handle the gesture or pass it down the hierarchy to viewA.
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate

You have to use the delegate method like this.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isDescendantOfView:(Your View)]) {
return YES;
}
return NO;
}
I hope it will help you.

Related

Are subviews automatically added as listeners to their superview's UIGestureRecognizers?

I have a swipe gesture attached to a UIView that doesn't seem to be registering when the swipe is on top of it's subviews.
One of solution is to check is gesture point inside your subview or not,
there is a useful C function:
/* Return true if `point' is contained in `rect', false otherwise. */
bool CGRectContainsPoint(CGRect rect, CGPoint point)
that you can use like this:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return CGRectContainsPoint(subview.frame, [touch locationInView:self.view]);;
}
The other solutions should work, but a potentially easier one is to set subview.userInteractionEnabled = false in the subview if it doesn't have its own event handlers.
Let's say A is the root UIView which you want to receive swipes, and B is a subview of A that you don't really want to receive swipes.
if you do not want to receive any gestures on B, you can userInteractionEnabled = false on it
if you still want to receive some gestures on B (but not a swipe)
you must subclass B so that you can implement this method, and implement this method in B
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([gestureRecognizer isKindOfClass:UISwipeGestureRecognizer]) {
return NO;
}
return YES;
}
You can also see how you may get a wide range of functionality from implementing gestureRecognizer:shouldReceiveTouch:

Adding a UIGestureRecognizer taking priority over all other interactions

When I tap on a UIButton, a UIView MyView appear from the bottom a cover a third of the screen. I would like that when I tap somewhere outside this view, it disappears.
I thought about adding another transparent UIView right under MyView and add a tab gesture on it with the dismiss function but I'm sure there is something cleaner than this.
So I thought about adding the tap gesture MyTapGesture to dismiss MyView on self.view of the UIViewController. The problem is that outside this view, I have other UIControls and gestures that capture also any touch at the same time than MyTapGesture.
How can I make MyTapGesture the priority gesture outside MyView and ignore all other gesture, taps, etc...?
You may have to use the gesture delegate methods to handle two tapGestureRecognizer activate the one you need depending on scenario
#pragma mark - UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([tapGestureRecognizer1 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer2 isEqual:otherGestureRecognizer];
}
if ([tapGestureRecognizer2 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer1 isEqual:otherGestureRecognizer];
}
return NO;
}

How to avoid to trigger a UIPanGestureRecognizer when there is a tap on a UIButton?

I have added UIPanGestureRecognizer on the view of my UIViewController.
In this view (a calculator) are some UIButton triggered by the event .TouchUpInside.
The problem comes if I tap on the button and make a small pan at the same time (which might happen if you tap quickly a button and are moving to the next one at the same time). Then the pan gesture is triggered. I would like to avoid it when there is a tap on a button. But I would like to allow it if the tap takes too long (let say 0.3s is enough to trigger the pan gesture).
How can I achieve that?
Set the property cancelsTouchesInView of your gesture recognizer to NO.
Then your button should work properly.
You can use the delegate method like this-
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isKindOfClass:[UIButton class]]) {
return NO;
}
return YES;
}
There is a dirty solution. You can just grab it in a UIScrollView

Enabling touch event on Objects In a UIScrollview

I've a scrollview that has a UIView on it and on those Views, there's a UIImageView on it, three UILabel on it, I want to enable user Interaction on it, but wouldn't work. I've enabled setUserInteraction for both the UIView, UIScrollView, UILabels, UIImageView none is Responding to click actions at all. The layout look like the Image Below....
implement
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
so the gestures of the uiscroll view won't conflict with the subview's recognisers
basically what happens is that the UIScrollView won't pass the events to its subviews because the default of the above method is to return NO
This sounds too easy to be the problem, but I've made the following mistake: Everything is set just right, but I did not drag out one of the SentEvents like TouchUpInside to an action in the implementation.
check this way,
1> first check whether your view controller respond to UIGestureRecognizerDelegate this way
#interface RootViewController : UIViewController<UIGestureRecognizerDelegate>
2> then in design check you map scrollview property and delegate properly
3> apply this code in viewDidload
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapditected)];
tapGesture.delegate = self;
// prevents the scroll view from swallowing up the touch event of child buttons
tapGesture.cancelsTouchesInView = NO;
[self.scroller addGestureRecognizer:tapGesture];
4> check you apply this code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
5> if all goes wll then this method should detected
-(void)tapditected{
}

Disable Touches on a view

Hi I have a UIView who's alpha is 0.7 and below it are some UITextFields. I don't want it to call touches events while keeping touches events. I tried using
[lightBoxView setUserInteractionEnabled:NO];
But now the UITextFields can become active or first responder. How can I disable it from calling touch events as well as not passing touches to others?
You also need to set the userInteractionEnabled = NO for all the subviews as well.
Try this,
[[lightBoxView subviews] makeObjectsPerformSelector:#selector(setUserInteractionEnabled:)
withObject:[NSNumber numberWithBool:NO]];
This will call setUserInteractionEnabled: on all direct subviews of lightBoxView and set it to NO. For a more complex subview hierarchy you will have to recursively loop through all the child views and disable the user interaction on each one. For this you can write a recursive method in a UIView category. For more details about this category method take a look at this answer.
Hope that helps!
You can remove those control from tough gesture delegate method.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UITextFiled class]])
{
return NO;
}
else
{
return YES;
}
}

Resources