0

I am trying to set up a tutorial type class that presents an overlay view and requires actions from the user before continuing. I currently have a hierarchy set up as follows.

UIWindow 
|---- UIViewController 
|     |---- UIViewA (View performing tutorial action on)
|     |---- UIViewB
|
|---- UIViewT (tutorial overlay)
      |---- CGRect (defined by UIViewA)

During the tutorial, views will get dragged around, new views will be created, etc, which is why I added the tutorial overlay view to the UIWindow. This way the I don't have to mess with the view hierarchy within the view controller as suggested in many places on SO. The purpose of the overlay window is to block all actions, except for the required action expected by the tutorial.

Currently the tutorial overlay view is implemented as follows

@interface ZSOverlayView : UIView <UIGestureRecognizerDelegate>

@property (nonatomic, assign) CGRect activeRegion;

@end

@implementation ZSOverlayView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    return !CGRectContainsPoint(_activeRegion, point);
}

@end

Where activeRegion is the CGRect defined by UIViewA. This successfully blocks all unwanted events and gestures from making it through the overlay, outside of the activeRegion. In this specific case UIViewB does not get the event or gestures.

The problem is that I only want a single gesture to make it through, not all of them, for UIViewA. For example if UIViewA has a double tap, pan, and custom gesture, I may only want the double tap to be active at once, or perhaps the custom gesture to be active at once, or perhaps both. The tutorial doesn't know what gestures the view has, so it needs a generic way of passing along the needed ones, and blocking the ones that aren't. Currently none of the gestures are blocked. Even if I have flags in place, which I currently do, that determine what gestures should be able to make it through, I am still running into problems in how to block specific ones, and let others through.

I'm unsure how to proceed because the tutorial overlay is not the delegate of any of the gesture recognizers, nor do I want it to be because by taking over as the delegate the tutorial might remove special conditions specified by the existing delegates.

Any ideas how to proceed to get the functionality I'm looking for?

Michael Hogenson
  • 1,292
  • 1
  • 15
  • 31
  • Could you clarify this statement: "nor do I want it to be in case of special situations that are taken care of by the proper delegate"? – Lyndsey Scott Feb 16 '14 at 06:55
  • I updated the end of the question, so hopefully it's more clear now. – Michael Hogenson Feb 16 '14 at 07:08
  • 1
    If I'm understanding correctly, you could set the UIGestureRecognizerDelegates then just use conditionals in the delegate methods to specify what to do when the gesture view is the tutorial window vs when the gesture view is the main window. – Lyndsey Scott Feb 16 '14 at 07:16
  • I've spent so much time going over different solutions, and I never thought of that one. I'm pretty sure that it will work but I'm trying to make the tutorial generic, without integrating it too heavily into existing code. Just to be clear, you're saying to modify the already existing delegates to act differently when the tutorial view is the gesture view? Is this the only way to effectively do it? – Michael Hogenson Feb 16 '14 at 07:22
  • Yes, that's what I'm saying. And I don't know of any other way of doing it other than modifying the existing delegate methods and adding those conditionals. – Lyndsey Scott Feb 16 '14 at 07:37

2 Answers2

0

Have you tried to just use -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ?

If you're wanting to block touch events for something, you can just do it here like:

  • Prevent touch events for a view
  • Call a helper method to determine which view(s) can be touched
  • etc.

Edit: Better late then never. I actually ran into needing to do this (again...) and (yet again) found the answer I was referring to in the comments below =]

Anyways, using touchesBegan, you could just do this ( to obtain all gesture recognizers who are receiving the type of touch ( or touches ) you are looking for:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    // In this example, I'm only actually looking for (and caring) about a single touch.
   if( [touches count] == 1 ) {
       UITouch *touch = (UITouch *)[touches anyObject];
       // So here they are now
       NSArray *gestureRecognizersForTouch = [touch.gestureRecognizers copy];
      // ... whatever else.
   }
}

At this point, you can either remove the recognizers, set a value to a property they all have access to in your object, submit a notification, etc. etc. etc.

Jonathon Hibbard
  • 1,547
  • 13
  • 20
  • I've looked at it but I don't think it will help because I need to let gestures through or block them and I couldn't find a way to create a UIGestureRecognizer from a UIEvent and a set of points. For example, I have no way of knowing whether the UIEvent is a double touch or a swipe, do I? – Michael Hogenson Feb 16 '14 at 07:33
  • here is a (overly complex) way of doing it: http://stackoverflow.com/questions/14726087/identifying-the-type-of-touch-gestures-from-uievent-object The other way would be to just create a generic Gesture recognizer and listen to all of the gestures (which is a pattern used all over the web). I had a good link for it, let me find it really quick. But then yeah, you should be able to do what you're looking for Bleh, here's that code I was talking about: (void)handleTapGesture:(UITapGestureRecognizer *)sender // sender.state == UIGestureRecognizerStateRecognized for instance – Jonathon Hibbard Feb 16 '14 at 07:38
  • meh, n/m sorry i can't find the link right now. i'll check back tomorrow andif no one has answered i'll find it and post it. (Fyi that code obviously only lists for tap-based gestures... but its a start =P ) – Jonathon Hibbard Feb 16 '14 at 07:45
0

I don't really like the solution, but the best answer was given by Lyndsey Scott in the comments.

If I'm understanding correctly, you could set the UIGestureRecognizerDelegates then just use conditionals in the delegate methods to specify what to do when the gesture view is the tutorial window vs when the gesture view is the main window.

I would have preferred not to rely on this method since I was trying to have my tutorial library do all of the work but since there hasn't been an answer in a while, I just wanted to throw it out there that this worked.

Michael Hogenson
  • 1,292
  • 1
  • 15
  • 31