Andreas Willadsen
Andreas Willadsen

Reputation: 373

UISlider inside UIPageViewController

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.

Upvotes: 13

Views: 3209

Answers (4)

mixtly87
mixtly87

Reputation: 1695

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.

Upvotes: 0

yhlin
yhlin

Reputation: 189

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);
}

Upvotes: 2

Sergey  Alpeev
Sergey Alpeev

Reputation: 518

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;
    }
}

Upvotes: 22

Valent Richie
Valent Richie

Reputation: 5226

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); 
}

Upvotes: 0

Related Questions