旋转时自动调整AVCaptureVideoPreviewLayer大小的问题

4

我编写了一个静态框架,在其中我有一个名为ViewfinderViewController的类,该类使用AVCaptureSession设置相机。此ViewController还将AVCaptureVideoPreviewLayer作为子层添加到其自身视图的层中:

    // code in ViewfinderViewController.m
    previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
    previewLayer.frame = self.view.bounds;
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:previewLayer];

视图查找器控制器还进行一些视频处理,并为框架的用户注册了一些委托方法,以防在其中一个处理过的帧中发现或未发现感兴趣的内容。
在我的真实应用程序的viewDidLoad方法中,我创建了一个ViewfinderViewController的实例,设置了它的frame并将它的视图添加为子视图。
    // code in the app's view controller viewDidLoad method
    ViewfinderViewController *vfVC = [[ViewfinderViewController alloc] init];
    vfVC.view.frame = self.view.bounds;
    [self.view addSubview:vfVC.view];

这个方案在忽略旋转的情况下运行良好(直到现在我才注意到这一点)。我的主要问题是,ViewfinderViewController.view 调整了它的框架大小,但 AVCaptureVideoPreviewLayer 没有。我有点困惑:难道预览层不应该自动调整大小,因为与其 superLayer 相对应的视图已正确调整大小吗?

有什么想法吗?我很乐意提供更多信息,但为了让问题更简洁,我暂时不会再深入探讨。谢谢。


从您的视图控制器的视图的- (void)layoutSubviews调用setNeedsLayout是否有帮助? - Josh Bleecher Snyder
1个回答

9

最后,我发现以下方法对我的应用程序效果最佳。 在我的应用程序中,我将ViewFinderViewController添加为子视图控制器:

- (void)viewWillAppear:(BOOL)animated;
{
    if ([self.childViewControllers containsObject:self.viewfinderViewController] == NO) {
        [self addChildViewController:self.viewfinderViewController];
        self.viewfinderViewController.view.frame = self.view.bounds;
        [self.view addSubview:self.viewfinderViewController.view];
        [self.viewfinderViewController didMoveToParentViewController:self];
    }
}

这样,willAnimateRotationToInterfaceOrientation: 方法将自动调用,这是我之前从将取景器视图添加为其子视图的视图控制器中转发的方法。
此外,在 ViewfinderViewController 的此方法中,我会更新 previewLayer 的大小:
- (void)viewWillLayoutSubviews;
{
    self.previewLayer.frame = self.view.bounds;
}

我通过实现以下两种方法来处理预览层的旋转:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];
    [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    [self updatePreviewLayerForOrientation:toInterfaceOrientation];
    [CATransaction commit];
}

- (void)updatePreviewLayerForOrientation:(UIInterfaceOrientation)interfaceOrientation;
{
    // correct position of previewLayer
    CGSize newSize = self.view.bounds.size;
    self.previewLayer.position = CGPointMake(0.5 * newSize.width, 0.5 * newSize.height);

    // rotate the previewLayer, in order to have camera picture right
    switch (interfaceOrientation) {
        case UIInterfaceOrientationPortrait:
            [self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(0)];
            break;

        case UIInterfaceOrientationLandscapeLeft:
            [self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI/2)];
            break;

        case UIInterfaceOrientationLandscapeRight:
            [self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(-M_PI/2)];
            break;

        case UIDeviceOrientationPortraitUpsideDown:
            [self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI)];
            break;

        default:
            break;
    }
}

我希望这能帮助那些将AVCaptureVideoPreviewLayer添加为子层并在界面旋转时遇到调整大小和方向问题的人。

+1 我错过了在viewWillLayoutSubviews中更新previewLayer的步骤...谢谢!! - Giuseppe Garassino

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