13

I have a PageViewController which is initialized like this:

self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
                          navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

On one of the pages, there's a UISlider.

My problem is that when I have transitionstyle set to UIPageViewControllerTransitionStyleScroll, it takes 150-200 ms before beginTrackingWithTouch is invoked on the slider. This behavior is not seen when I use UIPageViewControllerTransitionStylePageCurl, where the UISlider is selected instantly.

This means that unless the user waits a bit before dragging the slider (a video progress), the page will turn instead, which is far from ideal.

The Page curl animation does not meet the demands of the app, so any explanation or workaround is appreciated.

4 Answers4

22

Since with UIPageViewControllerTransitionStyleScroll gesture recognizers isn't available, you can use this:

for (UIView *view in pageViewController.view.subviews) {
    if ([view isKindOfClass:[UIScrollView class]]) {
        UIScrollView *scrollView = (UIScrollView *)view;
        scrollView.delaysContentTouches = NO;
    }
}
Sergey Alpeev
  • 518
  • 4
  • 13
  • Hi, I dont' understand how to use this solution ... Could you develop a bit more where to add this code, and why setting delaysContentTouches on the scrollView works ? Thanks – Frederic Adda Aug 29 '16 at 10:21
  • You can put this code in next line after creating your UIPageViewController. Or you can subclass UIPageViewController and put this code in viewDidLoad method, just use 'self' instead of 'pageViewController'. When 'delaysContentToushes' is 'NO', scroll view forwards touches to content immediately and didn't tries to perfrom scroll before content handles touches – Sergey Alpeev Aug 29 '16 at 11:56
  • Thanks for the explanation. It is a bit better for me, but the pageViewController still reacts first to a touch on the slider. – Frederic Adda Oct 20 '16 at 13:24
  • I don't get it either. I have no scroll view in my page subviews. just a slider – Dani Pralea Aug 23 '17 at 13:50
  • 1
    swift3: `for view in view.subviews { if view is UIScrollView { (view as! UIScrollView).delaysContentTouches = false } }` – StaRbUck42 Sep 14 '17 at 22:17
  • 1
    swift 4: `for view in pageVC.view.subviews { if let scrollView = view as? UIScrollView { scrollView.delaysContentTouches = false } }` – Siddhesh Mahadeshwar May 28 '19 at 02:24
2

I solved this issue by add a pan gesture on UISlider and set:

self.sliderGesture.cancelsTouchesInView = NO;  // make touch always triggered

and implement delegate method like:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return otherGestureRecognizer.view.superview == self.parentViewController.view;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // only receive touch in slider
    CGPoint touchLocation = [touch locationInView:self.view];
    return CGRectContainsPoint(self.slider.frame, touchLocation);
}
yhlin
  • 189
  • 2
  • 9
0

You can try to set the delegate of the page view controller gestures to the root view controller:

for (UIGestureRecognizer* gestureRecognizer in self.pageViewController.gestureRecognizers) {
    gestureRecognizer.delegate = self;
}

And then prevent the touch of the gestures if it appears inside UISlider which is a subclass of UIControl:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    return ([touch.view isKindOfClass:[UIControl class]] == NO); 
}
Valent Richie
  • 5,226
  • 1
  • 20
  • 21
  • Problem is gesturerecognizers isn't set when transitionstyle= UIPageViewControllerTransitionStyleScroll, hence this question: [link](http://stackoverflow.com/questions/13103613/uipageviewcontroller-returns-no-gesture-recognizers-in-ios-6) – Andreas Willadsen Jun 20 '13 at 12:00
0

What helped me was to add pan-gesture-recognizer to UIView which holds UISlider, so in the end I have UIPageViewController->UIScrollView->...->MyView->UISlider The 'MyView' thing had pan gesture registered to it which did nothing, but served just to NOT propagate events to scroll view.

mixtly87
  • 1,675
  • 15
  • 32