12

我已经实现了下面的代码来改变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;
}

这段代码几乎可以完美运行。但是,出现的一个问题是,如果您将 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];
    }
}

有谁知道为什么发生这种 180 度旋转时相机视图会颠倒?

4

2 回答 2

5

我相信它正在发生,因为viewDidLayoutSubviews当视图从纵向方向变为上下颠倒时不会被调用。当您快速旋转时,它会从一条直线转到另一条直线。如果您缓慢旋转,它会通过横向方向,因此viewDidLayoutSubviews会被调用,然后是您的方法。

我建议您使用在方向更改时调用的方法之一。我知道 Apple 建议越来越少地使用它们,因为他们希望视图在大小发生变化时发生变化,但是在某些情况下,例如,当您确实需要知道方向发生了变化时。

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

于 2015-06-23T14:24:57.990 回答
4

在解决我的问题之前,我遇到了同样的问题。

我声明了一个全局变量:

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

..

@end

implementation(.m 文件)下,我声明了 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];

}

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

抢夺我的-interfaceOrientationToVideoOrientation方法,它将与您那里的东西转换iOSDevice.orientation成相同的东西..AVCaptureVideoOrientation


(在我的情况下,我需要下面的这个功能,但看看它可能对你有用)

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

编辑

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

- (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在触发前先确定设备的旋转..

希望这对你有帮助..

于 2015-06-24T02:50:35.300 回答