取消交互式 UINavigationController 弹出手势不会调用 UINavigationControllerDelegate 方法 [英] Canceling interactive UINavigationController pop gesture does not call UINavigationControllerDelegate methods

查看:11
本文介绍了取消交互式 UINavigationController 弹出手势不会调用 UINavigationControllerDelegate 方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您拖动 UIViewController 的边缘以在 UINavigationController 内开始交互式弹出过渡,则当前下方的 UIViewController 具有 viewWillAppear: 被调用,然后是 UINavigationControllerDelegate 方法 navigationController:willShowViewController:animated:.

If you drag the edge of a UIViewController to begin an interactive pop transition within a UINavigationController, the UIViewController underneath the current has viewWillAppear: called, followed by the UINavigationControllerDelegate method navigationController:willShowViewController:animated:.

如果你取消转换(即被拖拽的控制器被放回原来的位置并且没有弹出),viewWillAppear:viewDidAppear: 会在顶视图控制器上被调用正如预期的那样,但委托方法 navigationController:willShowViewController:animated:navigationController:didShowViewController:animated: 不是.考虑到调用了 UIViewController 视图生命周期方法,似乎至少应该调用其中一个或两个.我想知道这是故意的还是 UINavigationController 中的错误.

If you cancel the transition (i.e. the dragged controller is placed back where it was and not popped), viewWillAppear: and viewDidAppear: are called on the top view controller as expected, but the delegate methods navigationController:willShowViewController:animated: and navigationController:didShowViewController:animated: aren't. It seems like at least one or both of these should be called considering the UIViewController view lifecycle methods are called. I am wondering whether this is deliberate or a bug in UINavigationController.

我真正需要的是能够在我的 UINavigationController 子类或其 UINavigationControllerDelegate 中查看何时取消交互式弹出.有没有明显的方法可以做到这一点?

What I really need is to be able to see when an interactive pop is cancelled, either within my UINavigationController subclass, or its UINavigationControllerDelegate. Is there an obvious way to do this?

编辑

我仍在寻找解决方案,但想提一下,我已将此问题报告为 Apple 的错误.查看文档,没有理由不调用这些委托方法,尤其是考虑到等效的视图生命周期方法确实会被调用.

I'm still looking for a solution to this but would like to mention that I have reported this issue as a bug with Apple. Looking at the documentation, there is no reason these delegate methods should not get called, especially considering the equivalent view lifecycle methods DO get called.

edit2

我的雷达票 (16823313) 已于今天(2015 年 5 月 21 日)关闭并标记为预期.:(

My radar ticket (16823313) was closed today (May 21st, 2015) and marked as intended. :(

工程部门已确定此问题的行为符合预期关于以下信息:

Engineering has determined that this issue behaves as intended based on the following information:

这实际上是正确的行为.导航过渡这是从 B -> A 发生的,如果你在过渡中取消它,你不会得到 didShowViewController: 方法.取消这个过渡不应被视为从 A -> B 的过渡,因为你从未真正到达过 A.

This is actually the correct behavior. The navigation transition that's happening from B -> A, if you cancel it mid-transition, you won't get the didShowViewController: method. A cancellation of this transition shouldn't be considered a transition from A -> B because you never actually reached A.

view[Will/Did]Appear 仍应按预期调用.

view[Will/Did]Appear should still be called as expected too.

这种情况真是太糟糕了,因为它违反直觉,但我下面答案中的解决方法在可预见的未来应该可以正常工作,至少对于我的用例而言.

Quite a bummer this is the case as it is counterintuitive but the workaround in my answer below should work fine for the foreseeable future, at least for my use-case.

推荐答案

对于任何感兴趣的人,我在 UINavigationControllerDelegate 级别找到了两种解决此问题的方法.

For anyone interested, I have found 2 ways to work around this at the UINavigationControllerDelegate level.

  1. 使用 KVO 观察 interactivePopGestureRecognizerstate 属性.不幸的是,取消转换不会将状态更改为 UIGestureRecognizerStateFailed,而只是 UIGestureRecognizerStateEnded,因此您需要编写一些额外的代码来跟踪发生的情况,如果您需要区分已取消或已完成的流行音乐.

  1. Use KVO to observe the state property of the interactivePopGestureRecognizer. Unfortunately, canceling the transition does not change the state to UIGestureRecognizerStateFailed but instead just UIGestureRecognizerStateEnded, so you would need to write a bit of additional code to keep track of what happened if you needed to discern between a cancelled or completed pop.

经过测试,这可能是更好的解决方案:使用 navigationController:willShowViewController:animated: 方法向过渡协调器添加通知块.它看起来像这样:

After testing it, this is probably the better solution: Use the navigationController:willShowViewController:animated: method to add a notification block to the transition coordinator. It looks something like this:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context)
    {
        if([context isCancelled])
        {
            UIViewController *fromViewController = [context viewControllerForKey:UITransitionContextFromViewControllerKey];
            [self navigationController:navigationController willShowViewController:fromViewController animated:animated];

            if([self respondsToSelector:@selector(navigationController:didShowViewController:animated:)])
            {
                NSTimeInterval animationCompletion = [context transitionDuration] * (double)[context percentComplete];

                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((uint64_t)animationCompletion * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self navigationController:navigationController didShowViewController:fromViewController animated:animated];
                });
            }


        }
    }];
}

起初我对使用此解决方案犹豫不决,因为文档不清楚您是否可以设置多个其中之一(因为在这种情况下,如果不知情的视图控制器也设置了自己的通知块,它可能会要么替换这个,要么被这个替换).不过经过测试,似乎不是1:1的关系,你可以安全地添加多个通知块.

I was hesitant to use this solution at first because the documentation was unclear about whether or not you could set more than one of these (since in that case, if an unknowing view controller also set its own notification block, it could potentially either replace this one or get replaced by this one). After testing it though, it appears that it is not a 1:1 relationship and you can add multiple notification blocks safely.

编辑

我编辑了上面的代码以延迟 navigationController:didShowViewController:animated: 调用仅在动画应该完成以更接近预期的默认行为时调用.

I edited the code above to delay the navigationController:didShowViewController:animated: call to only be called when the animation is supposed to be completed to more closely match the expected default behavior.

这篇关于取消交互式 UINavigationController 弹出手势不会调用 UINavigationControllerDelegate 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆