iOS 8中已弃用didRotateFromInterfaceOrientation。

5
自从iOS 8.0开始,函数didRotateFromInterfaceOrientation已被弃用,我现在不知道如何正确地改变AVCaptureVideoPreviewLayer的方向。根据"interfaceOrientation" is deprecated in iOS 8, How to change this method Objective C,我有以下可行的代码来获取基于statusBarOrientationAVCaptureVideoOrientation:
- (AVCaptureVideoOrientation)getOrientation {
    // Translate the orientation
    switch ([[UIApplication sharedApplication] statusBarOrientation]) {
        case UIInterfaceOrientationPortrait:
            return AVCaptureVideoOrientationPortrait;
        case UIInterfaceOrientationPortraitUpsideDown:
            return AVCaptureVideoOrientationPortraitUpsideDown;
        case UIInterfaceOrientationLandscapeLeft:
            return AVCaptureVideoOrientationLandscapeLeft;
        case UIInterfaceOrientationLandscapeRight:
            return AVCaptureVideoOrientationLandscapeRight;
        default:
            return AVCaptureVideoOrientationPortrait;
    }
}

当屏幕方向改变时,我需要调用以下函数:

[self.videoPreviewLayer.connection setVideoOrientation:[self getOrientation]];

但是我不知道把它放在哪里是正确的。

尝试1

由于didRotateFromInterfaceOrientation已经被弃用,苹果建议使用viewWillTransitionToSize:withTransitionCoordinator:,因此尝试以下代码似乎是自然的:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    [coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        [self.videoPreviewLayer.connection setVideoOrientation:[self getOrientation]];
    }];
}

但是,如果 UIViewController 被呈现出来,这个函数就不会被调用(根据“viewWillTransitionToSize:” not called in iOS 9 when the view controller is presented modally,这似乎是一个已知的 bug)。即使这个 bug 被解决了,还有另一个问题:方向变化并不等同于大小变化。例如,如果一个视图使用 UIModalPresentationFormSheet 呈现如下:
SecondViewController *vc = [[SecondViewController alloc] init];
vc.view.backgroundColor = [UIColor greenColor];
vc.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:vc animated:true completion:nil];

iPad在横屏和竖屏模式下,呈现的视图大小相同:

因此,我不能简单地使用viewWillTransitionToSize

尝试2

我注意到UIDeviceOrientationDidChangeNotification没有被弃用。太好了!我尝试注册一个带有该通知的通知:

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

    // Some other code to set up the preview layer 
    // ...

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(deviceOrientationDidChange:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void)deviceOrientationDidChange:(NSNotification *)notification {
    [self.videoPreviewLayer.connection setVideoOrientation:[self getOrientation]];
}

这几乎可以工作,而且非常接近了!问题是当我收到设备方向变化的通知时,旋转视图的动画可能已经开始,也可能没有。换句话说,如果设备已经倒置但动画仍在进行中,则返回值[[UIApplication sharedApplication] statusBarOrientation]可能不正确。

我不知道还有什么尝试的办法:(有任何想法吗?


为什么您不在“deviceOrientationDidChange”方法中使用UIDeviceOrientation,而不是状态栏方向?只需忽略.FaceUp和.FaceDown方向即可。 - almas
@almas,感谢您的评论。但问题在于设备方向与界面方向并不完全相同。可能会出现设备颠倒,但视图不支持.FaceDown的情况。如果我能保证当前视图支持所有四个方向,那么,是的,我认为您的建议在这里是可以的! - Yuchen
好的,你只需忽略应用程序不支持的所有方向,例如,你可以忽略FaceUp,FaceDown和PortraitUpsideDown。试一下,我相信它会起作用的。 - almas
1个回答

4
以下代码应该能够在Swift 2.1中正确处理视频预览的方向:
override func viewWillAppear(animated: Bool) {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self,
        selector: Selector("deviceOrientationDidChange:"),
        name: UIDeviceOrientationDidChangeNotification,
        object: nil)
}

override func viewDidDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self)
    super.viewDidDisappear(animated)
}

func deviceOrientationDidChange(sender: AnyObject) {
    let deviceOrientation = UIDevice.currentDevice().orientation;
    switch (deviceOrientation)
    {
    case .Portrait:
       previewLayer.connection.videoOrientation = .Portrait
    case .LandscapeLeft:
       previewLayer.connection.videoOrientation = .LandscapeRight
    case .LandscapeRight:
        previewLayer.connection.videoOrientation = .LandscapeLeft
    case .PortraitUpsideDown:
       previewLayer.connection.videoOrientation = .PortraitUpsideDown
    default:
        break
    }
}

1
我希望苹果公司能够在幕后实现您的方式。做得好。您仍然可以使用已弃用的“didRotate”,但是您的实现实际上考虑了一些“didRotate”没有考虑到的边缘情况。 - ScottyBlades

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