8

这仅在 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

返回零。

然后应用程序将崩溃。

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

有没有其他人经历过这个或指出如果我做错了什么?

非常感谢斯图尔特。

4

4 回答 4

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:

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

于 2012-09-27T16:27:16.523 回答
7

我相信我找到了一个解决方案,它比重构任何现有的 pageViewController 代码(如 noRema 所提到的那样,或者像这里所提到的那样搞乱选择器转发)要复杂得多,尽管如果没有这两个解决方案作为参考,我永远不会找到它。

这应该很容易放入任何 UIPageViewController 项目中,只需稍作调整。

要实现,您将代码保持原样;所有现有逻辑都应保持不变,因为这只影响 UIGestureRecognizer 委托行为。覆盖手势委托方法 - (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;
}
于 2012-10-04T18:41:12.693 回答
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标志设置为YESalways 并且用户根本无法浏览页面。注意:仅在 iOS 6 中发生。

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

通过添加如下方法:

- (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 标志的循环问题。

希望这对某人有帮助。

于 2012-11-26T09:35:12.370 回答
2

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

上述解决方案都不适合我,但我最终发现将以下行从移动viewDidLoadviewDidAppear完全修复它。

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
于 2012-11-19T17:21:55.640 回答