iOS设备快速旋转180度会导致摄像头倒置

iOS设备快速旋转180度会导致摄像头倒置,ios,objective-c,uiinterfaceorientation,avcapturesession,viewdidlayoutsubviews,Ios,Objective C,Uiinterfaceorientation,Avcapturesession,Viewdidlayoutsubviews,我已经实现了下面的代码,以基于UIInterfaceOrientation更改AVCaptureVideoSession的方向: - (AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation:(UIInterfaceOrientation)orientation { switch (orientation) { case UIInterfaceOrientationPortrait:

我已经实现了下面的代码,以基于
UIInterfaceOrientation
更改
AVCaptureVideoSession
的方向:

- (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;
}
这段代码工作得几乎完美。但是,出现的一个问题是,如果将iOS设备快速旋转180度,相机将倒置显示

以下是旋转前摄影机视图的外观:

这是旋转后的样子:

此外,下面是我的
viewdilayoutsubviews
的实现:

- (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];
    }
}

有人知道为什么在180度旋转时相机视图会颠倒吗?

我相信这是因为当视图从纵向更改为向上时,
viewdilayoutsubviews
不会被调用。当你旋转得很快时,它会从一个直线转到另一个直线。如果旋转速度缓慢,它将穿过横向方向,因此会调用
viewdilayoutsubviews
,然后调用您的方法

我建议您使用方向改变时调用的方法之一。我知道苹果建议越来越少地使用它们,因为它们希望在大小改变时视图也会改变,但也有一些情况,比如,当你真的需要知道方向改变时

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


UIApplicationIDChangeStatusBaroOrientationNotification

在此之前,我遇到了相同的问题,解决了我的问题

我声明了一个全局变量:

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

..

@end
实现
(.m文件)下,我在
-视图下声明了NSNotification observer,如下所示:

@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];

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

在我的
-InterfaceOrientationVideoOrientation
方法中获取一个战利品,它将
iOSDevice.orientation
转换为
AVCaptureVideoOrientation
与您的相同


(在我的例子中,我需要下面的这些函数,但出于某种原因,请看一下它可能对您有用)

编辑

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

- (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        

}
注:

使用
NSNotificationCenter
在触发之前,先确定要旋转的设备


希望这对你有帮助

我在Apple tools中看到过这一点,所以我不确定这是不是你的bug。@PaulCezanne啊,真有趣!哪一个?我只是想在camera应用程序上复制它,但没能做到。我在camera和消息中看到过它,但也许我是通过消息启动camera的。我想不起来了。我也认为这在iOS8.0中发生得更多,我不记得最近从相机上看到过,但我确实在8.3中看到了从消息启动相机时的旋转奇怪现象。@PaulCezanne Weird…我只是尝试通过从消息启动相机来测试,但也没有看到。我以前也有过同样的问题,我提出的解决方案是添加NSNotificationCenter,当通知直接以通知所针对的方法触发时,更改
previewLayer
的方向。。我现在不能给你一个密码这里太晚了我的密码在办公室里。。嗯……我明白了,那是有道理的。因此,您建议将我当前拥有的代码放入
viewdilayoutsubviews
中,类似于
-(void)orientationChanged:(NSNotification*)通知
adjustViewsForOrientation
,对吗?我想您只需要将最后一个
if
放入
orientationChanged:
。处理视图大小调整的其余代码很好地放在了
viewdilayoutsubviews
中。我不认为每次调用该方法时都应该添加该子层。这也是有意义的。您认为在哪里添加子层更合适?(很抱歉提出这些问题,这已经伤了我的头一段时间了,哈哈)。您可能可以检查它是否有
超层
,只有在没有的情况下才添加它。对于Swift 3.0-NotificationCenter.default.addObserver(self,selector:#selector(deviceRotated)(通知:),名称:NSNotification.name.uiApplicationIDChangeStatusBarOrientation,对象:。无)这几乎可以完美地工作!我现在唯一的问题是,如果我在iPad上运行应用程序并以横向模式启动,相机视图将以横向模式显示。如果我将设备旋转到纵向,然后再旋转回横向,相机将正确显示。@narner,关于这一点,您需要检查
-viewDidLoad
内的方向。。对于默认设置。。对不起,我没有把这个包括在这里。。我以为你已经有了那一个…这是有道理的。那么,像“previewLayer.connection.videoOrientation=[[UIDevice currentDevice]orientation];”?不完全需要
-interface-orientation-videoorientation
方法中转换的方向。。我将尝试编辑我的答案:)@纳纳:好了,试试看……)
- (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        

}