UIPanGestureRecognizer won't pan right - ios

I have a UIView subclass to which I have added a UIPanGestureRocognizer:
_panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePanGesture:)];
_panGestureRecognizer.maximumNumberOfTouches = 1;
_panGestureRecognizer.delegate = self;
[self addGestureRecognizer:_panGestureRecognizer];
This view is used in a view hierarchy which includes a UISplitViewController as the top-level view/controller.
When testing this in the iPad simulator in landscape orientation, if I start the pan by going up/down/left, my handlePanGesture: method is called as expected. However, if I start the pan by going right then my handlePanGesture: method is not called. Why not?

While I was writing up this question, I figured out the answer for myself:
The UISplitViewController since iOS 5 will, by default, recognize a swipe gesture to the right and display the popover controller. This is obvious in portrait orientation, however, in landscape orientation, the gesture has no apparent effect because the left-side view displayed as the popover in portrait is always displayed in landscape.
The solution to this is to disable the swipe gesture for the UISplitViewController with:
splitViewController.presentsWithGesture = NO;
I don't know if there is a way to have both gestures work.

Related

I've hidden the navigation bar and the status bar, now the screen edge pan gesture to go back won't work, is this typical?

I'm curious, if I set the navigationBar to hidden, and also hide the status bar, my view controller no longer responds to the screen edge gesture to pop the view controller.
Is this expected behaviour? I tried to set the interactivePopGestureRecognizer to enabled in viewDidLoad after I hide the navigation bar, but it still won't work.
[self.navigationController.navigationBar setHidden:YES];<--doesn't remove pop gesture
[self.navigationController setNavigationBarHidden:YES];<-- disables pop gesture
Simply use the first option, and in your root controller's viewDidAppear method use:
[self.navigationController.navigationBar setHidden:NO];
Are you sure you've done things right? I've put together an example that seems to work for me. All I did was make the navigationController.navigationBar.hidden = YES and [[UIApplication sharedApplication] setStatusBarHidden:YES]
-edit-
After closer inspection, it looks like there are two different properties on UINavigationController. There is navigationBar which is the UINavigationBar view, and there is navigationBarHidden which is a boolean. When you set navigationBarHidden to true, the swipe gesture stops working. But if you set that actual view to be hidden with navigationBar.hidden then the gesture still works. Check the Git repository for an example.
A very simple work around:
Link a swipe gesture method to your navigation back button. Make the current view controller the target of the gesture recognizer (self), with the selector popThisViewController. Then install the gesture recognizer into the view that the user will swipe on. Don't forget to add your go back action
edit added swipe gesture for reference to other coders that don't know
Cleaner code will look like this:
UISwipeGestureRecognizer *gesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(goBack:)];
gesture.numberOfTouchesRequired = 1;
gesture.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:swipeRight];
}
-(IBAction)goBack:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}

Swipe gesture being added to a UIView or UIViewController upon segue

I'm completely stumped by this. I've been working on a project that has both a landscape view and portrait view. I segue from one view controller to another, and the 2nd view controller has a UIView that allows custom drawing. However, when I'm in landscape mode (and only when in landscape mode), I'm unable to draw in the view (with touches... functions) because when I'm in the left half of the view and I drag towards the left side of the screen, I get taken back to the previous view controller.
The view controllers are embedded in a navigation controller, so I'm not sure if this is some built-in segue that the navigation controller creates to send me back or something, but other than that there's nothing I can think of that'd be causing this.
Any idea what may be causing this? I've already checked the UIView itself and there are no gesture recognizers associated with it, so I don't know where it'd be hiding.
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Add this to you viewDidLoad function of your second view controller.
iOS 7 and above has a feature to go back to previous view controller when swipe from the left end
UPDATE
self.navigationController.interactivePopGestureRecognizer.delegate = self
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer!) -> Bool {
return false;
}

Multiple visible views responding to one gesture recognizer

I have a view controller that consists of three views (self.panedview, self.view, self.sineview) When a swipe up gesture is detected, the highest view (self.panedview) is moved up halfway - revealing two additional views (self.view and self.sineview). self.sineview is a UIView that constantly has an animation running that renders a moving sinewave and takes up half of self.view. I have a swipe down gesture recognizer that works when I swipe down on self.panedview, but doesn't work when I swipe down on self.sineview. If I swipe around self.sineview on self.view it seems to work. When I hide self.sineview and swipe directly down on either self.view or self.paned view, the swipe down works. do you think the animating sine wave gets in the way of the gesture recognition.
UISwipeGestureRecognizer * swipeDownRec = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleDownSwipe:)];
[self.panedView addGestureRecognizer:swipeDownRec];
[self.view addGestureRecognizer:swipeDownRec];
[self.sineview addGestureRecognizer:swipeDownRec];
Also I tried varying between these two lines of code but there is no difference:
[self.view insertSubview:self.sineWave belowSubview:self.panedView];
[self.view insertSubview:self.sineWave aboveSubview:self.view];
I also tried adding a separate swipe down gesture recognizer for each view, but it still doesn't work.
The problem was the that the swipe recognizer for self.sinewave couldn't be recognized while the self.sinewave animation was enabled. The solution is simple: add UIViewAnimationOptionAllowUserInteraction as a parameter to the options handler for animateWithDuration:delay:options:animations:completion:

cameraOverlayView prevents editing with allowsEditing

Editing a photo after it's been taken (moving and scaling it) works fine in my app with this line:
[imagePicker setAllowsEditing:YES];
But if I also use a cameraOverlayView, the editing mode doesn't work anymore. The screen comes up, but pan and pinch gestures don't make anything happen.
I'm using your average image picker controller:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
And I add a camera overlay view, created from a custom view controller's view:
CameraOverlayViewController *overlayController = [[CameraOverlayViewController alloc] init];
UIView *overlayView = overlayController.view;
[imagePicker setCameraOverlayView:overlayView];
In IB, that view is set up to enable user interaction and multiple touch, which allows it to zoom and focus while taking the picture. But once the picture is taken and it enters editing mode, you cannot pan or pinch to move or scale the photo.
What am I missing?
Does your overlay take up the entire space of the camera view? If so, touches are going to the overlay instead of the view below, even if you have a transparent background.
Add this method to your overlay view and it will ignore touches so that they are passed to the views below. (You are overriding a method of UIView that detects touches.)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return NO;
}
Note: as well as that fantastic tip, you may also want to use this piece of info, to remove your overlay view, at that stage: UIImagePicker cameraOverlayView appears on Retake screen

Detecting touches with stacked Views & passing Touch events from a UIScrollView

I'm trying to close a pop-up menu if the user selects anywhere EXCEPT with-in the bounds of the pop-up itself. In other words, they select the background, the pop-up closes.
I currently have a RootViewController that loads a UIView with a bunch of other UI Elements.
At one point, a pop-up (custom) menu is rendered - this is a separate UIViewController with associated .xib. Its loaded on the screen by:
SectionsChooserViewController *cv = [[SectionsChooserViewController alloc] initWithNibName:#"SectionsChooserViewController" bundle:[NSBundle mainBundle]];
cv.view.frame = CGRectMake(584, 391, 314, 346);
cv.delegate = self;
This view occupies only a small portion of the screen. So added detect code for touches to this view will only register the callback if you're ON the view.
If I don't handle touches in the "SectionsChooserViewController" and instead implement the touchesBegan in the rootViewController (which loads the "SectionsChooser...") it doesn't get called for 90% of the view because the UIScrollView's that I have seem to register the touch and not pass it on.
Is there a way to make the UIScrollView pass the touch event?
Edit: At least I think the UIScrollView's are taking the touch event. I'm not sure - I have nearly 20 UI Controls on the page.
Edit: Ok, it is the UIScrollView. If I turn off interaction-enabled on both scrollView's the UIView will get the touches, but this breaks the UIScrollViews - so that won't work.
You might be able to use [super touchesBegan:withEvent:] to help solve the problem.
Depending on what your trying to do you might be able to use UIGestureRecognizer to capture the touch events.
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleDoubleTap:)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2; //change value to 1 for single taps
[self addGestureRecognizer:doubleTapGestureRecognizer];

Resources