Uipageviewcontroller Gesture Recognizers

UIPageViewController Gesture recognizers

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
}

Access UIPageViewController gesture recognizer(s) to enable swipe to delete

The gestures are attached to its scrollView, and this one is not a public attribute. Anyway I use this extension to get the scrollView :

extension UIPageViewController {

public var scrollView: UIScrollView? {
for view in self.view.subviews {
if let scrollView = view as? UIScrollView {
return scrollView
}
}
return nil
}

}

Then you want its panGesture :

pageController.scrollView?.panGestureRecognizer

UIPageViewController returns no Gesture Recognizers in iOS 6

There is a bug filed in radar for this behavior. So, I bet that until Apple fixes it there will be no chance to solve this.

One workaround that comes to my mind is laying a transparent subview on top of your UIPageViewController and add to it a UIPanGestureRecognizer to intercept that kind of gesture and not forward further. You could enable this view/recognizer when disabling the gesture is required.

I tried it with a combination of Pan and Tap gesture recognizers and it works.

This is my test code:

- (void)viewDidLoad {
[super viewDidLoad];

UIPanGestureRecognizer* g1 = [[[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(g1Pan:)] autorelease];
[self.view addGestureRecognizer:g1];

UITapGestureRecognizer* s1 = [[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(g1Tap:)] autorelease];

[self.view addGestureRecognizer:s1];

UIView* anotherView = [[[UIView alloc]initWithFrame:self.view.bounds] autorelease];
[self.view addSubview:anotherView];

UIPanGestureRecognizer* g2 = [[[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(g2Pan:)] autorelease];
[anotherView addGestureRecognizer:g2];

}

When g2 is enabled, it will prevent g1 from being recognized. On the other hand, it will not prevent s1 from being recognized.

I understand this is hack, but in the face of a seeming bug in UIPageViewController (at least, actual behavior is blatantly different from what the reference states), I cannot see any better solution.

How to tell whether a UIPageViewController page turn is due to a swipe/pan or a tap

The question is really how to determine which of several gesture recognizers is responsible for something happening.

The key thing to understand is that any gesture recognizer can have more than one target/action installed. The UIPageViewController sets its own target/actions internally, but that doesn't preclude others being added.

When setting up a sub-class of UIPageViewController after it has been loaded, or instantiated, add the following code (or Swift code equivalent):

for (UIGestureRecognizer *gr in self.gestureRecognizers) {
if ([gr class] == [UIPanGestureRecognizer class])
[gr addTarget:self action:@selector(panGestureOccurred)];
else if ([gr class] == [UITapGestureRecognizer class])
[gr addTarget:self action:@selector(tapGestureOccurred)];
}

Then, add the two target/action methods to the sub-class:

- (void)tapGestureOccurred
{
// Set a flag here to rely on later after the page turn
}

- (void)panGestureOccurred
{
// Reset a flag here to rely on later after the page turn
}

This obviously generalizes for any other types of gestures, but currently only the pan and tap gestures appear to be supported by a UIPageViewController.

panGestureOccurred will be called multiple times while the user is touching the screen and moving a finger/stylus. The tapGestureOccurred is only called once.

But only one of the two methods will be called, depending on which gesture recognizer the page view controller in its infinite wisdom decides wins. This all seems to work much more robustly than the too-low level touchesBegan and touchesMoved idea posited in the original question.

UIPageViewController detecting pan gestures

I figured out how to do this. Basically a UIPageViewController uses UIScrollViews as its subviews. I created a loop and set all the subviews that are UIScrollViews and assigned their delegates to my ViewController.

/**
* Set the UIScrollViews that are part of the UIPageViewController to delegate to this class,
* that way we can know when the user is panning left/right
*/
-(void)initializeScrollViewDelegates
{
UIScrollView *pageScrollView;
for (UIView* view in self.pageViewController.view.subviews){
if([view isKindOfClass:[UIScrollView class]])
{
pageScrollView = (UIScrollView *)view;
pageScrollView.delegate = self;
}
}
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
NSLog(@"Im scrolling, yay!");
}

Customizing UIPageViewController gesture recognizers Scroll behavior

After trying so many hacks, I finally got solution.

What i did, first got the pageviewcontroller scorll view in a property

for (UIView *view in mypageviewcontroller.view.subviews) {
if([view isKindOfClass:[UIScrollView class]])
{
pagescrollview= (UIScrollView *)view;
}
}

Then assigned pan gesture to pageviewcontroller scorllview and gesture delegate.

UIPanGestureRecognizer* g1 = [[UIPanGestureRecognizer alloc] initWithTarget:self                                                       action:@selector(gesture)];

[g1 setDelegate:self];

[pagescrollview addGestureRecognizer:g1];

Then in gesture delegate , i checked whether the gesture starts from my desire points, if starts from a location that should scroll pageviewcontroller then this delegate method should return no to enable original pagescorllview gesture to receive pan gesture.

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {

CGPoint touchPoint = [touch locationInView:self.view];
if(floor(NSFoundationVersionNumber)<=NSFoundationVersionNumber_iOS_6_1)
touchPoint.y -=44;
else
touchPoint.y -=64;

PGNavigationController *nav =ViewControllerArray[VisiblePageindex];
PageContentVC *pagecontentvc = ((PageContentVC *) nav.visibleViewController);

if (touchPoint.y > pagecontentvc.leftpanalbtn.frame.origin.y && (pagecontentvc.leftpanalbtn.frame.size.height+pagecontentvc.leftpanalbtn.frame.origin.y )>touchPoint.y && touchPoint.x >pagecontentvc.leftpanalbtn.frame.origin.x
&& touchPoint.x<(pagecontentvc.leftpanalbtn.frame.origin.x+pagecontentvc.leftpanalbtn.frame.size.width)) {
return NO;
}
else if (touchPoint.y > pagecontentvc.rightpanalbtn.frame.origin.y && (pagecontentvc.rightpanalbtn.frame.size.height+pagecontentvc.rightpanalbtn.frame.origin.y )>touchPoint.y && touchPoint.x >pagecontentvc.rightpanalbtn.frame.origin.x
&& touchPoint.x<(pagecontentvc.rightpanalbtn.frame.origin.x+pagecontentvc.rightpanalbtn.frame.size.width))
{

return NO;
}
if( touchPoint.y>282 && touchPoint.x>118 &&touchPoint.y<282+75 && touchPoint.x < 118+85)
{
return NO;
}
// else if()
}
return YES;
}

hope it help someone else.

how to block swipe gesture of UIPageViewController in swift?

You can use the below extension enable or disable the SwipeGesture

extension UIPageViewController {

func enableSwipeGesture() {
for view in self.view.subviews {
if let subView = view as? UIScrollView {
subView.isScrollEnabled = true
}
}
}

func disableSwipeGesture() {
for view in self.view.subviews {
if let subView = view as? UIScrollView {
subView.isScrollEnabled = false
}
}
}
}


Related Topics



Leave a reply



Submit