UIViewController动画等待动画完成

4
我正在使用这个观察者:UIDeviceOrientationDidChangeNotification 来检测用户何时更改设备方向。当方向变为横向时,我会呈现一个新的 UIViewController,或者在他将其改回纵向时解除显示此 UIViewController

我的问题是,当用户快速多次旋转设备时,应用程序会变得混乱,直到出现以下错误:

警告:尝试呈现 在不在窗口层次结构中的视图上!`。

等待动画结束然后再改变旋转的最佳方式是什么?

这就是我在呈现视图控制器上使用的内容:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self beginDeviceOrientationListener];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)beginDeviceOrientationListener
{
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
}

- (void)orientationChanged:(NSNotification *)notification
{
    UIDevice *device = notification.object;
    switch (device.orientation)
    {
        case UIDeviceOrientationLandscapeLeft:
        case UIDeviceOrientationLandscapeRight:
        {
            TheViewControllerToPresent *viewController = [[TheViewControllerToPresent alloc] init];
            [self presentViewController:viewController animated:YES completion:nil];
            [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationLandscapeRight] forKey:@"orientation"];
            [[UIApplication sharedApplication] setStatusBarOrientation:[[[UIDevice currentDevice] valueForKey:@"orientation"] integerValue] animated:YES];
            [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
        }
            break;

        default:
            break;
    }
}

这是我在呈现视图控制器上使用的内容:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self beginDeviceOrientationListener];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)beginDeviceOrientationListener
{
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
}

- (void)orientationChanged:(NSNotification *)notification
{
    UIDevice *device = notification.object;
    switch (device.orientation)
    {
        case UIDeviceOrientationPortrait:
        {
            [self dismissViewControllerAnimated:YES completion:nil];
            [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationPortrait] forKey:@"orientation"];
            [[UIApplication sharedApplication] setStatusBarOrientation:[[[UIDevice currentDevice] valueForKey:@"orientation"] integerValue] animated:YES];
        }
            break;
        default:
            break;
    }
}

你为什么要设置 [UIDevice orientation]?这是什么可怕的黑客手段? - Sulthan
好的,它实际上运行得非常好,为什么要使用hack?我应该使用什么代替? - ytpm
[UIDevice orientation] 是只读的,这是有原因的。黑客技巧在于使用反射(setValue:)访问它,规避了 readonly 状态。如果您不想使用控制器默认的旋转支持,可以在呈现控制器的视图上使用 transform - Sulthan
1个回答

3
我正在使用的最简单的解决方案是在动画进行时阻止用户进行任何更改。
这可以通过在动画开始时添加以下代码来完成:
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];

并将其传递给完成处理程序:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];

用户可以旋转设备,但在动画期间不会生成事件,因此动画不会发生冲突。然而,当动画结束时,您应该明确检查方向:

UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

查看是否应该启动另一个动画。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接