I have a UIPageViewController load with my Viewcontroller.
The view controllers have buttons which are overridden by the PageViewControllers gesture recognizers.
For example I have a button on the right side of the viewcontroller and when you press the button, the PageViewController takes over and changes the page.
How can I make the button receive the touch and cancel the gesture recognizer in the PageViewController?
I think the PageViewController makes my ViewController a subview of its view.
I know I could turn off all of the Gestures, but this isn't the effect I'm looking for.
I would prefer not to subclass the PageViewController as apple says this class is not meant to be subclassed.
Here is another solution, which can be added in the viewDidLoad
template right after the self.view.gestureRecognizers = self.pageViewController.gestureRecognizers
part from the Xcode template. It avoids messing with the guts of the gesture recognizers or dealing with its delegates. It just removes the tap gesture recognizer from the views, leaving only the swipe recognizer.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
// Find the tap gesture recognizer so we can remove it!
UIGestureRecognizer* tapRecognizer = nil;
for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) {
if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
tapRecognizer = recognizer;
break;
}
}
if ( tapRecognizer ) {
[self.view removeGestureRecognizer:tapRecognizer];
[self.pageViewController.view removeGestureRecognizer:tapRecognizer];
}
Now to switch between pages, you have to swipe. Taps now only work on your controls on top of the page view (which is what I was after).
You can override
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
to better control when the PageViewController should receive the touch and not. Look at "Preventing Gesture Recognizers from Analyzing Touches" in Dev API Gesture Recognizers
My solution looks like this in the RootViewController for the UIPageViewController:
In viewDidLoad:
//EDITED Need to take care of all gestureRecogizers. Got a bug when only setting the delegate for Tap
for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
gR.delegate = self;
}
The override:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
//Touch gestures below top bar should not make the page turn.
//EDITED Check for only Tap here instead.
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
CGPoint touchPoint = [touch locationInView:self.view];
if (touchPoint.y > 40) {
return NO;
}
else if (touchPoint.x > 50 && touchPoint.x < 430) {//Let the buttons in the middle of the top bar receive the touch
return NO;
}
}
return YES;
}
And don't forget to set the RootViewController as UIGestureRecognizerDelegate.
(FYI, I'm only in Landscape mode.)
EDIT - The above code translated into Swift 2:
In viewDidLoad:
for gr in self.view.gestureRecognizers! {
gr.delegate = self
}
Make the page view controller inherit UIGestureRecognizerDelegate
then add:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if let _ = gestureRecognizer as? UITapGestureRecognizer {
let touchPoint = touch .locationInView(self.view)
if (touchPoint.y > 40 ){
return false
}else{
return true
}
}
return true
}
I had the same problem. The sample and documentation does this in loadView or viewDidLoad:
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
This replaces the gesture recognizers from the UIViewControllers views with the gestureRecognizers of the UIPageViewController. Now when a touch occurs, they are first sent through the pageViewControllers gesture recognizers - if they do not match, they are sent to the subviews.
Just uncomment that line, and everything is working as expected.
Phillip
Setting the gestureRecognizers delegate to a viewController as below no longer work on ios6
for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
gR.delegate = self;
}
In ios6, setting your pageViewController's gestureRecognizers delegate to a viewController causes a crash
In newer versions (I am in Xcode 7.3 targeting iOS 8.1+), none of these solutions seem to work.
The accepted answer would crash with error:
UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.
The currently highest ranking answer (from Pat McG) no longer works as well because UIPageViewController
's scrollview seems to be using odd gesture recognizer sub classes that you can't check for. Therefore, the statement if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] )
never executes.
I chose to just set cancelsTouchesInView on each recognizer to false, which allows subviews of the UIPageViewController
to receive touches as well.
In viewDidLoad
:
guard let recognizers = self.pageViewController.view.subviews[0].gestureRecognizers else {
print("No gesture recognizers on scrollview.")
return
}
for recognizer in recognizers {
recognizer.cancelsTouchesInView = false
}
I used
for (UIScrollView *view in _pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
view.delaysContentTouches = NO;
}
}
to allow clicks to go through to buttons inside a UIPageViewController
In my case I wanted to disable tapping on the UIPageControl and let tapping being received by another button on the screen. Swipe still works. I have tried numerous ways and I believe that was the simplest working solution:
for (UIPageControl *view in _pageController.view.subviews) {
if ([view isKindOfClass:[UIPageControl class]]) {
view.enabled = NO;
}
}
This is getting the UIPageControl view from the UIPageController subviews and disabling user interaction.
Just create a subview (linked to a new IBOutlet gesturesView) in your RootViewController and assign the gestures to this new view. This view cover the part of the screen you want the gesture enable.
in viewDidLoad change :
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
to :
self.gesturesView.gestureRecognizers = self.pageViewController.gestureRecognizers;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With