我有一个UIView
@property (nonatomic, strong) IBOutlet UIView *previewView;
previewView
将最终使用以下预览图层显示我的相机在我的相机上进行的预览。
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
我在故事板中的previewView
上设置了约束,因此遇到了以下问题。
self.previewLayer.frame = self.previewView.bounds; // This doesn't work
self.previewLayer.videoGravity = AVLayerVideoGravityResize;
[self.previewView.layer addSublayer:self.previewLayer];
previewLayer
被添加到previewView subLayer中,但它没有显示在正确的参数(宽度和高度)中。我认为这是由于在autolayout上使用约束。
我该如何解决这个问题?
更新:我还尝试了以下内容:
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspect;
CALayer *rootLayer = [previewView layer];
rootLayer.frame = self.previewView.bounds;
[rootLayer setMasksToBounds:YES];
[self.previewLayer setFrame:[rootLayer bounds]];
[rootLayer addSublayer:self.previewLayer];
它似乎显示如下:http://cl.ly/image/3T3o0O1E3U17
近距离接触,但仍然非常接近。
答案 0 :(得分:12)
好的,我解决了。
问题在于,当您使用自动布局时,previewLayer
的子视图的边框/界限可能会在设置previewLayer
后更改,而不会{ {1}}本身也相应更新!这是因为CALayer
s的布局完全由一个人自己的代码控制(另见相关答案:https://stackoverflow.com/a/27735617/623685)。
要解决此问题,您必须覆盖viewDidLayoutSubviews
的{{1}}方法,以便每次子视图的布局更改时更新UIViewController
的位置和边界(以及可能的其他位置)
在下文中,我将描述我是如何详细解决的:
我的情况实际上有点复杂,因为我使用的是OpenCV iOS框架2.4.9。这里,预览层由名为previewLayer
的OpenCV类创建和管理。因此,我必须创建一个CvVideoCamera
的子类,我在其中添加了以下方法:
CvVideoCamera
说明:- (void)updatePreviewLayer
{
self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height);
[self layoutPreviewLayer];
}
是您传递给parentView
的UIView,以指定预览图层的位置以及应该有多大。 CvVideoCamera
是由CvVideoCamera管理的预览图层。 customPreviewLayer
是一种基本上更新图层位置的方法:https://github.com/Itseez/opencv/blob/2.4/modules/highgui/src/cap_ios_video_camera.mm#L211
然后我简单地从我的UIViewController调用这个方法,如下所示:
layoutPreviewLayer
答案 1 :(得分:1)
主要思想是相同的 - 当使用Autolayout
时,需要在应用所有视图约束后设置预览图层的框架。 viewDidLayoutSubviews
方法用于此 - 与原始答案相同,但没有使用除Apple AVFoundation
以外的任何框架的复杂性。
以下代码基于Apple的示例(AVCam-iOS: Using AVFoundation to Capture Images and Movies)。但是代码被修改为使用updateViewConstraints
方法以编程方式设置所有约束,而不是样本中使用的Storyboard方法。相关片段如下所示:
@interface QRScannerViewController ()
@property (nonatomic) UIView *previewView;
@end
@implementation QRScannerViewController
{
AVCaptureSession *_captureSession;
AVCaptureVideoPreviewLayer *_captureVideoPreviewLayer;
dispatch_queue_t _sessionQueue;
}
#pragma mark - Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.previewView];
_captureSession = [AVCaptureSession new];
_captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_captureSession];
_captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
_sessionQueue = dispatch_queue_create("av_session_queue", DISPATCH_QUEUE_SERIAL);
[self.view setNeedsUpdateConstraints];
dispatch_async(_sessionQueue, ^{
[self configureCaptureSession];
});
[self.previewView.layer addSublayer:_captureVideoPreviewLayer];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (_isCaptureDeviceConfigured) {
[_captureSession startRunning];
}
}
- (void)viewDidLayoutSubviews
{
_captureVideoPreviewLayer.frame = self.previewView.bounds;
}
#pragma mark - getters / initializers
- (UIView *)previewView
{
if (_previewView) {
return _previewView;
}
_previewView = [UIView new];
_previewView.backgroundColor = [UIColor blackColor];
_previewView.translatesAutoresizingMaskIntoConstraints = NO;
return _previewView;
}
- (void)configureCaptureSession
{
[_captureSession beginConfiguration];
// Code omitted, only relevant to the preview layer is included. See the Apple's sample for full code.
...
_captureVideoPreviewLayer.connection.videoOrientation = initialVideoOrientation;
...
}
#pragma mark - Autolayout
- (void)updateViewConstraints
{
[self.previewView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor constant:0.0].active = YES;
[self.previewView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:-40.0].active = YES;
[self.previewView.widthAnchor constraintEqualToConstant:300].active = YES;
[self.previewView.heightAnchor constraintEqualToAnchor:self.previewView.widthAnchor constant:0.0].active = YES;
[super updateViewConstraints];
}