iOS设备的快速180度旋转会导致相机倒置

nar*_*ner 11 objective-c uiinterfaceorientation ios avcapturesession viewdidlayoutsubviews

我已经实现了下面的代码来改变AVCaptureVideoSession基于以下内容的方向UIInterfaceOrientation:

- (AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation:(UIInterfaceOrientation)orientation {
    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            return AVCaptureVideoOrientationPortrait;
        case UIInterfaceOrientationPortraitUpsideDown:
            return AVCaptureVideoOrientationPortraitUpsideDown;
        case UIInterfaceOrientationLandscapeLeft:
            return AVCaptureVideoOrientationLandscapeLeft;
        case UIInterfaceOrientationLandscapeRight:
            return AVCaptureVideoOrientationLandscapeRight;
        default:
            break;
    }
    NSLog(@"Warning - Didn't recognise interface orientation (%ld)",(long)orientation);
    return AVCaptureVideoOrientationPortrait;
}
Run Code Online (Sandbox Code Playgroud)

这段代码几乎完美无缺.但是,出现的一个问题是,如果您快速将iOS设备旋转180度,相机将显示为颠倒.

以下是旋转前相机视图的样子:

在此输入图像描述

这是旋转后的样子:

在此输入图像描述

另外,这是我的实现viewDidLayoutSubviews:

- (void)viewDidLayoutSubviews {

    [super viewDidLayoutSubviews];

    previewLayer.frame = self.view.bounds;

    self.view.translatesAutoresizingMaskIntoConstraints = NO;
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:previewLayer];

    if (previewLayer.connection.supportsVideoOrientation) {
        previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
    }
}
Run Code Online (Sandbox Code Playgroud)

这个180度旋转发生时有没有人知道为什么摄像机视图会颠倒?

pte*_*fil 5

我相信它正在发生,因为viewDidLayoutSubviews当视图从纵向方向更改为UpsideDown时,不会调用它.当你快速旋转时,它会从一个直线转到另一个直线.如果你慢慢旋转它会通过横向方向,因此viewDidLayoutSubviews被调用,然后调用你的方法.

我建议你使用方向更改时调用的方法之一.我知道Apple建议越来越少地使用它们,因为它们希望在大小改变时改变视图,但是有些情况下,例如当你真的需要知道方向改变时.

例如,您可以注册接收此通知: UIApplicationDidChangeStatusBarOrientationNotification


0ye*_*eoj 4

我之前也遇到过同样的问题,这解决了我的问题。

我声明了一个全局变量:

@interface YourViewController ()
{
    ...
    UIDevice *iOSDevice;
}

..

@end
Run Code Online (Sandbox Code Playgroud)

在(.m文件)下implementation我声明了NSNotification观察者,如下-viewWillAppear所示:

@implementation YourViewController

-(void)viewWillAppear:(BOOL)animated
{
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

    [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification  object:[UIDevice currentDevice]];

}

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

- (void)orientationChanged:(NSNotification *)notification
{
    iOSDevice = notification.object;

    previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation];

    //or

    [self setAutoVideoConnectionOrientation:YES];

}
Run Code Online (Sandbox Code Playgroud)

我创建了一个返回复制的当前设备的方向的函数,例如:

看看我的-interfaceOrientationToVideoOrientation方法,它会将其转换iOSDevice.orientationAVCaptureVideoOrientation与您那里相同的内容。


(就我而言,我需要下面的这个功能,但看看它可能出于某种原因对你有用)

- (AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation
{
    switch (iOSDevice.orientation) {

        case UIInterfaceOrientationPortraitUpsideDown:

            return AVCaptureVideoOrientationPortraitUpsideDown;

        case UIInterfaceOrientationLandscapeLeft:

            return AVCaptureVideoOrientationLandscapeLeft;

        case UIInterfaceOrientationLandscapeRight:

            return AVCaptureVideoOrientationLandscapeRight;

        default:
        case UIDeviceOrientationPortrait:
            return AVCaptureVideoOrientationPortrait;
    }
}

- (AVCaptureConnection *)setAutoVideoConnectionOrientation:(BOOL)status
{
    AVCaptureConnection *videoConnection = nil;

    //This is for me
    //for (AVCaptureConnection *connection in stillImageOutput.connections) {

    //This might be for you
    for (AVCaptureConnection *connection in previewLayer.connection) {

        for (AVCaptureInputPort *port in [connection inputPorts])
        {
            if ([[port mediaType] isEqual:AVMediaTypeVideo])
            {
                videoConnection = connection;

                if (status == YES)
                {
                    [videoConnection setVideoOrientation:[self interfaceOrientationToVideoOrientation]];
                }
                else
                {
                    [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
                }
            }
            if (videoConnection)
            {
                break;
            }
        }
    }
    return videoConnection;
}
Run Code Online (Sandbox Code Playgroud)

编辑

对于默认方向:您需要检查“当前”方向。

- (void)viewDidLoad
{
    [super viewDidLoad];

    // assuming you finish setting the `previewLayer`

    ..
    // after all of that code, when the view is ready for displaying
    // if you implemented this approach the best thing to do is:

    // set this 
    iOSDevice = [UIDevice currentDevice];

    // then call 
    previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation];
    // to update the `previewLayer.connection.videoOrientation ` for default orientation        

}
Run Code Online (Sandbox Code Playgroud)

笔记:

使用NSNotificationCenter让设备的旋转在触发之前先被解决。

希望这对你有帮助..