在ios 6中,将uipageViewController gestureRecognizers委托设置为viewController会导致崩溃

时间:2012-09-24 08:27:48

标签: objective-c ios xcode ios6

这只是在ios6上开始发生,但是如果你使用页面视图控制器模板启动一个新项目。然后在

PCRootViewControlle::viewDidLoad()

将这些行添加到方法的底部。

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

您需要分配viewController,使其符合UIGestureRecognizerDelegate并实现方法

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch (UITouch *)touch
{
    return YES;
}

现在,如果您运行应用程序并尝试将页面超出界限,即转到1月并尝试返回

  • (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController

返回nil。

该应用程序将崩溃。

ios5没有发生这种情况。我需要将gestureRecognizer委托分配给我的viewController,因为我并不总是希望pageViewController处理触摸事件。

还有其他人经历过这个或指出我是否做错了什么?

非常感谢 斯图尔特。

4 个答案:

答案 0 :(得分:8)

终于找到了解决我问题的办法,这让我感到悲痛,所以希望这可以帮助别人。

问题是如果将pageViewControllers委托设置为viewController

for (UIGestureRecognizer *gR in self.pageController.view.gestureRecognizers) 
{
    if ([gR isKindOfClass:[UITapGestureRecognizer class]])
    {
        gR.enabled = NO;
    }
    else if ([gR isKindOfClass:[UIPanGestureRecognizer class]])
    {
        gR.delegate = self;
    }
}

然后从

返回nil
pageViewController:viewControllerAfterViewController:

会崩溃!仅限iOS6 !!

我的问题是我需要设置gestureRecognisers的委托,因为我需要在某些情况下拦截panGesture,即由于那里的某些按钮而不允许用户翻页,因为触摸了某些部分。

解决方案是从

中提取逻辑
pageViewController:viewControllerAfterViewController: 

进入

gestureRecognizer:shouldReceiveTouch:

因为只要我们从那里返回NO,它就不会继续打电话

pageViewController:viewControllerAfterViewController:

所以不需要返回nil并且崩溃。

但是,这在序列的第一页和最后一页上不起作用。例如,在第一页上,您希望允许页面向前但不向后。所以我想看看传入的GestureRecogniser,将其投射到PanGesture,然后检查速度,如果速度表示转回(>> 0.0f),则返回NO。听起来不错,但速度始终为零。

然后我在GestureRecognizer委托上找到了一个非常有用的小函数:

gestureRecognizerShouldBegin:gestureRecognizer

之后调用此函数
gestureRecognizer:shouldReceiveTouch:

但是这次手势的速度与我预期的一样,所以我可以检查速度,如果是>则只返回第一页的YES。 0.0F

答案 1 :(得分:7)

我相信我找到的解决方案比重构任何现有的pageViewController代码要复杂得多,如noRema所提到的,或者如同here那样搞乱选择器转发,尽管我没有找到它那些解决方案作为参考。

只需稍作调整即可轻松进入任何UIPageViewController项目。

要实现,请按原样保留代码;所有现有逻辑应保持不变,因为这只会影响UIGestureRecognizer Delegate行为。覆盖手势委托方法 - (BOOL)gestureRecognizerShouldBegin:具有以下内容:

注意:我使用Apple的基于页面的应用程序代码作为起点,因此,如果术语_modelController_pageViewController引起混淆,请参阅。

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{

    //Make sure we're not trying to turn backward past the first page:
    if ([_modelController indexOfViewController:[_pageViewController.viewControllers objectAtIndex:0]] == 0) {
        if ([(UIPanGestureRecognizer*)gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
            [(UIPanGestureRecognizer*)gestureRecognizer velocityInView:gestureRecognizer.view].x > 0.0f) {
            NSLog(@"DENIED SWIPE PREVIOUS ON FIRST PAGE");
            return NO;
        }
        if ([(UITapGestureRecognizer*)gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
            [(UITapGestureRecognizer*)gestureRecognizer locationInView:gestureRecognizer.view].x < self.view.frame.size.width/2) {
            NSLog(@"DENIED TAP PREVIOUS ON FIRST PAGE");
            return NO;
        }
    }

    //Make sure we're not trying to turn forward past the last page:
    int finalVCindexSubtractor;
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
        // the vc we compare is a different distance from the end based on our orientation:
        finalVCindexSubtractor = 2;
    } else {
        finalVCindexSubtractor = 1;
    }
    if ([_modelController indexOfViewController:[_pageViewController.viewControllers objectAtIndex:0]] == _modelController.pageData.count-finalVCindexSubtractor) {
        if ([(UIPanGestureRecognizer*)gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
            [(UIPanGestureRecognizer*)gestureRecognizer velocityInView:gestureRecognizer.view].x < 0.0f) {
            NSLog(@"DENIED SWIPE NEXT ON LAST PAGE");
            return NO;
        }
        if ([(UITapGestureRecognizer*)gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] &&
            [(UITapGestureRecognizer*)gestureRecognizer locationInView:gestureRecognizer.view].x > self.view.frame.size.width/2) {
            NSLog(@"DENIED TAP NEXT ON LAST PAGE");
            return NO;
        }
    }
    return YES;
}

答案 2 :(得分:4)

在iOS 6下的UIPageViewController中调查Pan Gesture的问题时,我注意到它可以在一个手势中多次在视图控制器方法之前/之后调用。这在我的特定情况下是不好的,因为我需要等到动画完成每页翻页才能导航到下一页/上一页。 因此,我们的方法具有这样的结构:

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    if (animationInProgress)
        return nil;
    UIViewController *result = nil;
    //do stuff to init result controller for next/prev page
    if (result)
        animationInProgress = YES;
    return result;
}

viewControllerAfterViewController方法相同。

动画结束后,调用UIPageViewControllerDelegate的这个方法:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
        animationInProgress = NO;
        //do other stuff to handle finishing animation.
}

由于PanGesture被多次调用,然后viewControllerAfterViewController和另一个方法被调用了几次,并且在这种情况下不会调用didFinishAnimating方法导致animationInProgress标志始终设置为YES,用户根本无法浏览页面。注意:仅在iOS 6中发生。

要解决这个问题,我们必须以某种方式处理PanGesture。使用UIView gestureRecognizerShouldBegin:gestureRecognizer(在iOS 6中添加)根本没有解决问题,将控制器设置为手势的委托导致崩溃,当从方法之前/之后返回nil时。因此,在PanGesture处于UIGestureRecognizerStateChanged状态的情况下,我们尝试添加逻辑以在控制器方法之前/之后不调用(基于某些测试来调查它以确定在循环中调用方法时的手势状态)。 p>

添加如下方法:

- (BOOL)skipIfPanGestureInProgress {
    BOOL shouldSkip = NO;
    if(pvcPanGestureRecognizer && [pvcPanGestureRecognizer state] == UIGestureRecognizerStateChanged){
        animationInProgress = NO;
        shouldSkip = YES;
    }
    return shouldSkip;
}

之后的方法如下:

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    if([self skipIfPanGestureInProgress]){
        return nil;
    }
    if (animationInProgress)
        return nil;
    UIViewController *result = nil;
    //do stuff to init result controller for next/prev page
    if (result)
        animationInProgress = YES;
    return result;
}

这有助于解决animationInProgress标志的循环问题。

希望这会对某人有所帮助。

答案 3 :(得分:2)

我遇到了同样的问题,UIPageViewController与iOS6崩溃时导航超出界限时出现相同的错误。

以上解决方案均不适合我,但我最终发现将以下行从viewDidLoad移至viewDidAppear完全修复了此问题。

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;