AVCaptureVideoPreviewLayer ориентация - нужно пейзаж
Мое приложение только в альбомной ориентации. Я представляю слой AVCaptureVideoPreviewLay следующим образом:
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
[self.previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
NSLog(@"previewView: %@", self.previewView);
CALayer *rootLayer = [self.previewView layer];
[rootLayer setMasksToBounds:YES];
[self.previewLayer setFrame:[rootLayer bounds]];
NSLog(@"previewlayer: %f, %f, %f, %f", self.previewLayer.frame.origin.x, self.previewLayer.frame.origin.y, self.previewLayer.frame.size.width, self.previewLayer.frame.size.height);
[rootLayer addSublayer:self.previewLayer];
[session startRunning];
self.previewView имеет рамку (0,0,568,320), что является правильным. self.previewLayer регистрирует фрейм (0,0,568,320), что теоретически правильно. Однако дисплей камеры отображается в виде портретного прямоугольника в центре экрана с альбомной ориентацией, а ориентация изображения предварительного просмотра камеры неправильна на 90 градусов. Что я делаю неправильно? Мне нужно, чтобы слой предварительного просмотра камеры отображался в полноэкранном режиме, в альбомном режиме, и изображение должно быть правильно ориентировано.
20 ответов
Ориентация камеры по умолчанию - альбомная ориентация (кнопка "Домой" слева). Вам нужно сделать две вещи здесь:
1- Измените кадр предварительного просмотра на:
self.previewLayer.frame=self.view.bounds;
Вам необходимо установить рамку слоя предварительного просмотра в соответствии с границами экрана, чтобы при вращении экрана рамка слоя предварительного просмотра изменялась (вы не можете использовать рамку корневого представления, потому что это не изменяется при вращении, но границы корневого просмотра делать). В вашем примере вы устанавливаете фрейм Previewlayer в свойство previewView, которое я не вижу.
2- Вам необходимо повернуть соединение слоя предварительного просмотра с вращением устройства. Добавьте этот код в viewDidAppear:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
//Get Preview Layer connection
AVCaptureConnection *previewLayerConnection=self.previewLayer.connection;
if ([previewLayerConnection isVideoOrientationSupported])
[previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}
Надеюсь, это решит это.
Полное раскрытие: это упрощенная версия, так как вам все равно, вправо или влево.
ЛУЧШИЙ ОТВЕТ НА SWIFT 3.0 И XCODE 8.0
private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
layer.videoOrientation = orientation
previewLayer.frame = self.view.bounds
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let connection = self.previewLayer?.connection {
let currentDevice: UIDevice = UIDevice.current
let orientation: UIDeviceOrientation = currentDevice.orientation
let previewLayerConnection : AVCaptureConnection = connection
if previewLayerConnection.isVideoOrientationSupported {
switch (orientation) {
case .portrait: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
break
case .landscapeRight: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)
break
case .landscapeLeft: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)
break
case .portraitUpsideDown: updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)
break
default: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
break
}
}
}
}
ЛУЧШИЙ ОТВЕТ НА SWIFT 2.2 И XCODE 7.3
private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
layer.videoOrientation = orientation
previewLayer.frame = self.view.bounds
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let connection = self.previewLayer?.connection {
let currentDevice: UIDevice = UIDevice.currentDevice()
let orientation: UIDeviceOrientation = currentDevice.orientation
let previewLayerConnection : AVCaptureConnection = connection
if (previewLayerConnection.supportsVideoOrientation) {
switch (orientation) {
case .Portrait: updatePreviewLayer(previewLayerConnection, orientation: .Portrait)
break
case .LandscapeRight: updatePreviewLayer(previewLayerConnection, orientation: .LandscapeLeft)
break
case .LandscapeLeft: updatePreviewLayer(previewLayerConnection, orientation: .LandscapeRight)
break
case .PortraitUpsideDown: updatePreviewLayer(previewLayerConnection, orientation: .PortraitUpsideDown)
break
default: updatePreviewLayer(previewLayerConnection, orientation: .Portrait)
break
}
}
}
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
if let connection = self.previewLayer?.connection {
var currentDevice: UIDevice = UIDevice.currentDevice()
var orientation: UIDeviceOrientation = currentDevice.orientation
var previewLayerConnection : AVCaptureConnection = connection
if (previewLayerConnection.supportsVideoOrientation) {
switch (orientation) {
case .portrait:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portrait
break
case .landscapeRight:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.landscapeRight
break
case .landscapeLeft:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
break
case .portraitUpsideDown:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
break
default:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portrait
break
}
}
}
}
API, похоже, несколько изменился. videoOrientation
теперь свойство на слое предварительного просмотра connection
имущество. Кроме того, нет необходимости использовать переключатель. Ответ для Swift 3.0:
override func viewDidLayoutSubviews() {
self.configureVideoOrientation()
}
private func configureVideoOrientation() {
if let previewLayer = self.previewLayer,
let connection = previewLayer.connection {
let orientation = UIDevice.current.orientation
if connection.isVideoOrientationSupported,
let videoOrientation = AVCaptureVideoOrientation(rawValue: orientation.rawValue) {
previewLayer.frame = self.view.bounds
previewLayer.connection?.videoOrientation = videoOrientation
}
}
}
Мы не можем использовать
[previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
так как UIInterfaceOrientation != AVCaptureVideoOrientation
Но мы можем просто проверить значения... и это работает, с помощью следующего кода.
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
switch (orientation) {
case UIInterfaceOrientationPortrait:
[_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
break;
case UIInterfaceOrientationPortraitUpsideDown:
[_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
break;
case UIInterfaceOrientationLandscapeLeft:
[_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
break;
case UIInterfaceOrientationLandscapeRight:
[_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
break;
}
}
Для тех, кто борется за полнофункциональный предварительный просмотр камеры. Вот производственный код. Конечно, недостатком является задержка при изменении ориентации. Если у кого есть лучшее решение для преодоления этого, пожалуйста, поделитесь
- (void)viewDidLoad
{
[super viewDidLoad];
[self initCamera];
}
- (void)initCamera
{
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
if (captureInput) {
mSession = [[AVCaptureSession alloc] init];
[mSession addInput:captureInput];
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
if ([mSession isRunning]) {
[mSession stopRunning];
[mCameraLayer removeFromSuperlayer];
[self initCamera];
[self startCamera];
}
}
- (void)startCamera
{
[mSession startRunning];
Settings::getInstance()->setClearColor(Color(0, 0, 0, 0));
mCameraLayer = [AVCaptureVideoPreviewLayer layerWithSession: mSession];
[self updateCameraLayer];
[mCameraView.layer addSublayer:mCameraLayer];
}
- (void)stopCamera
{
[mSession stopRunning];
[mCameraLayer removeFromSuperlayer];
Settings::getInstance()->setDefClearColor();
}
- (void)toggleCamera
{
mSession.isRunning ? [self stopCamera] : [self startCamera];
[mGLKView setNeedsDisplay];
}
- (void)updateCameraLayer
{
mCameraLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
mCameraLayer.frame = mCameraView.bounds;
float x = mCameraView.frame.origin.x;
float y = mCameraView.frame.origin.y;
float w = mCameraView.frame.size.width;
float h = mCameraView.frame.size.height;
CATransform3D transform = CATransform3DIdentity;
if (UIDeviceOrientationLandscapeLeft == [[UIDevice currentDevice] orientation]) {
mCameraLayer.frame = CGRectMake(x, y, h, w);
transform = CATransform3DTranslate(transform, (w - h) / 2, (h - w) / 2, 0);
transform = CATransform3DRotate(transform, -M_PI/2, 0, 0, 1);
} else if (UIDeviceOrientationLandscapeRight == [[UIDevice currentDevice] orientation]) {
mCameraLayer.frame = CGRectMake(x, y, h, w);
transform = CATransform3DTranslate(transform, (w - h) / 2, (h - w) / 2, 0);
transform = CATransform3DRotate(transform, M_PI/2, 0, 0, 1);
} else if (UIDeviceOrientationPortraitUpsideDown == [[UIDevice currentDevice] orientation]) {
mCameraLayer.frame = mCameraView.bounds;
transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
} else {
mCameraLayer.frame = mCameraView.bounds;
}
mCameraLayer.transform = transform;
}
enter code here
Поскольку при использовании вышеупомянутого решения есть предупреждение об устаревании и преобразовании, а настройка videoOrientation, похоже, не работает в iOS7, я установил проверки на ориентацию в моем геттере для AVCaptureVideoPreviewLayer, например, так:
- (AVCaptureVideoPreviewLayer *) previewLayer
{
if(!_previewLayer)
{
_previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession: self.captureSession];
[_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
_previewLayer.frame = self.view.bounds; // Assume you want the preview layer to fill the view.
[_previewLayer setPosition:CGPointMake(0,0)];
if (UIDeviceOrientationLandscapeLeft == [[UIDevice currentDevice] orientation]) {
_previewLayer.transform = CATransform3DMakeRotation(-M_PI/2, 0, 0, 1);
}
else if (UIDeviceOrientationLandscapeRight == [[UIDevice currentDevice] orientation])
{
_previewLayer.transform = CATransform3DMakeRotation(M_PI/2, 0, 0, 1);
}
}
return _previewLayer;
}
Работает со Swift 4, Xcode 9:
override func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator)
{
super.viewWillTransition(to: size, with: coordinator)
guard
let conn = self.previewLayer?.connection,
conn.isVideoOrientationSupported
else { return }
let deviceOrientation = UIDevice.current.orientation
switch deviceOrientation {
case .portrait: conn.videoOrientation = .portrait
case .landscapeRight: conn.videoOrientation = .landscapeLeft
case .landscapeLeft: conn.videoOrientation = .landscapeRight
case .portraitUpsideDown: conn.videoOrientation = .portraitUpsideDown
default: conn.videoOrientation = .portrait
}
}
Одна тонкость, чтобы заметить здесь, что UIDeviceOrientation.landscapeRight
подходит к AVCaptureVideoOrientation.landscapeLeft
,
Другой случай ландшафта также не соответствует. Это является преднамеренным и учитывает неудачное несоответствие между UIKit и AVFoundation. Если вы сопоставляете дела, сопоставляя имена, это не сработает, и ваше видео будет перевернуто в альбомной конфигурации.
Версия Swift 5
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updatePreview()
}
func updatePreview() {
let orientation: AVCaptureVideoOrientation
switch UIDevice.current.orientation {
case .portrait:
orientation = .portrait
case .landscapeRight:
orientation = .landscapeLeft
case .landscapeLeft:
orientation = .landscapeRight
case .portraitUpsideDown:
orientation = .portraitUpsideDown
default:
orientation = .portrait
}
if previewLayer?.connection?.isVideoOrientationSupported == true {
previewLayer?.connection?.videoOrientation = orientation
}
previewLayer.frame = view.bounds
}
Выбранный ответ работает для Swift 4.2 - Xcode 10.0 - iOS 12.0:
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let previewLayerConnection = self.videoPreviewLayer?.connection, previewLayerConnection.isVideoOrientationSupported {
updatePreviewLayer(layer: previewLayerConnection, orientation: UIApplication.shared.statusBarOrientation.videoOrientation)
}
}
private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
layer.videoOrientation = orientation
videoPreviewLayer?.frame = self.view.bounds
}
Не забудьте сопоставить UIInterfaceOrientation с AVCaptureVideoOrientation
extension UIInterfaceOrientation {
public var videoOrientation: AVCaptureVideoOrientation {
switch self {
case .portrait:
return AVCaptureVideoOrientation.portrait
case .landscapeRight:
return AVCaptureVideoOrientation.landscapeRight
case .landscapeLeft:
return AVCaptureVideoOrientation.landscapeLeft
case .portraitUpsideDown:
return AVCaptureVideoOrientation.portraitUpsideDown
default:
return AVCaptureVideoOrientation.portrait
}
}
}
Правильное отображение из UIDeviceOrientation
в AVCaptureVideoOrientation
является необходимым.
Если ваше приложение поддерживает device rotation
, resizing preview.frame
также необходимо, и это func
должен быть вызван из viewDidLayoutSubviews()
а также viewWillTransition()
,
private func configureVideoOrientation() {
if let preview = self.previewLayer,
let connection = preview.connection {
let orientation = UIDevice.current.orientation
if connection.isVideoOrientationSupported {
var videoOrientation: AVCaptureVideoOrientation
switch orientation {
case .portrait:
videoOrientation = .portrait
case .portraitUpsideDown:
videoOrientation = .portraitUpsideDown
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
default:
videoOrientation = .portrait
}
preview.frame = self.view.bounds
connection.videoOrientation = videoOrientation
}
}
}
Привет, ребята, спасибо за все ответы и отзывы по этому поводу, я сталкивался с этим, когда я работаю над быстрым приложением. Вы можете заставить камеру вращаться вместе с вашим устройством, используя этот код:
override func shouldAutorotate() -> Bool {
if your cameraController.previewLayer.connection != nil {
var currentDevice: UIDevice = UIDevice.currentDevice()
var orientation: UIDeviceOrientation = currentDevice.orientation
var previewLayerConnection : AVCaptureConnection = your cameraController.previewLayer.connection
if (previewLayerConnection.supportsVideoOrientation)
{
switch (orientation)
{
case .Portrait:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
break
case .LandscapeRight:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeLeft
break
case .LandscapeLeft:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeRight
break
default:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
break
}
}
}
return true
}
Надеюсь это поможет!
Сначала нам нужно создать AVCaptureVideoPreviewLayer и:
- установите его videoGravity (поскольку в моем случае я использую небольшой вид для получения видео).
установить кадр.
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; [_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
установить ориентацию изначально
if (_videoPreviewLayer.connection.supportsVideoOrientation) { _videoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation]; }
установить ориентацию для каждого случая, используя простой переключатель
-(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 (%d)",orientation); return AVCaptureVideoOrientationPortrait;
}
- Поскольку устройство поддерживает как landscapeLeft, так и landscapeRight, используйте делегат, вызываемый при вращении:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{ if (_videoPreviewLayer.connection.supportsVideoOrientation) { _videoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:toInterfaceOrientation]; } }
Я тоже столкнулся с тем же. Это должно было исправить ориентацию камеры.
override func shouldAutorotate() -> Bool {
return false
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return UIInterfaceOrientation.LandscapeLeft
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.LandscapeLeft
}
Починить камеру
let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.avCaptureSession)
previewLayer.frame = self.view.layer.frame
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
Улучшенная версия ответа Маселко
Работает просто отлично!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let connection = previewView.connection {
if connection.isVideoOrientationSupported {
let videoOrientation = AVCaptureVideoOrientation.init(rawValue: UIApplication.shared.statusBarOrientation.rawValue)!
connection.videoOrientation = videoOrientation
previewView.frame = self.view.bounds
}
}
}
Ответ Маселко почти сработал для меня, за исключением того, что если ориентация строки состояния меняется, то выход камеры отображается вверх ногами. Я решил эту проблему, повторно вызвав логику Маселко, когда строка состояния переворачивается.
Вот мое модифицированное решение Maselko (протестировано на ios12/swift4):
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setCameraOrientation()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
setCameraOrientation()
}
@objc func setCameraOrientation() {
if let connection = self.previewLayer?.connection {
let currentDevice: UIDevice = UIDevice.current
let orientation: UIDeviceOrientation = currentDevice.orientation
let previewLayerConnection : AVCaptureConnection = connection
if previewLayerConnection.isVideoOrientationSupported {
let o: AVCaptureVideoOrientation
switch (orientation) {
case .portrait: o = .portrait
case .landscapeRight: o = .landscapeLeft
case .landscapeLeft: o = .landscapeRight
case .portraitUpsideDown: o = .portraitUpsideDown
default: o = .portrait
}
previewLayerConnection.videoOrientation = o
previewLayer!.frame = self.view.bounds
}
}
}
Ответ @Maselko правильный, но с одной стороны: вы должны использовать UIApplication.shared.statusBarOrientation
вместо UIDevice.current.orientation
потому что ориентация устройства - это то, как ваше устройство физически расположено. Он ломается, когда ваше устройство находится в альбомной ориентации, но ваш пользовательский интерфейс не поддерживает эту ориентацию (например, когда я делал приложение для камеры только в альбомной ориентации и запускал вид, когда устройство находится в книжной ориентации).
private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
layer.videoOrientation = orientation
previewLayer.frame = self.view.bounds
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let connection = self.previewLayer?.connection {
let currentDevice: UIDevice = UIDevice.current
let orientation = UIApplication.shared.statusBarOrientation
let previewLayerConnection : AVCaptureConnection = connection
if previewLayerConnection.isVideoOrientationSupported {
switch (orientation) {
case .portrait: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
break
case .landscapeRight: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)
break
case .landscapeLeft: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)
break
case .portraitUpsideDown: updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)
break
default: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
break
}
}
}
}
Вот решение, которое я использую с Swift 4.
Это коротко и прекрасно работает для меня.
open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let videoLayer = self.previewLayer
coordinator.animate(alongsideTransition: { (context: UIViewControllerTransitionCoordinatorContext) in
guard let connection = videoLayer?.connection, connection.isVideoOrientationSupported, let orientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue) else {
return
}
connection.videoOrientation = orientation
videoLayer?.frame = self.view.bounds
}) { (context: UIViewControllerTransitionCoordinatorContext) in
// handle any completion logic here...
}
}
Я столкнулся с той же проблемой при настройке контроллера просмотра камеры.
Позволить виду вращаться вместе с компоновкой, а затем зафиксировать previewOrientation по пути — не лучший подход к этому по двум причинам: во-первых, кадр на самом деле будет вращаться, что кажется очень неестественным, даже если мы исправим ориентацию предварительного просмотра по пути. Во-вторых, поскольку камера физически прикреплена к устройству и, следовательно, вращается вместе с ним, мы действительно хотим зафиксировать преобразование кадра предварительного просмотра в портретном режиме. Очевидно, что содержимое предварительного просмотра будет естественным образом вращаться вместе с физической камерой.
Решения, предполагающие наличие отдельного контроллера представления для блокировки поворота интерфейса для представления предварительного просмотра, не работали, когда я пробовал.
Я закончил тем, что предложил решение Apple, опубликованное в этом техническом вопросе и ответе, и добился успеха:
«Предотвращение вращения представления» https://developer.apple.com/library/archive/qa/qa1890/_index.html
При использовании этого метода анимация поворота кадра, которая применяется к предварительному просмотру, отменяется, и предварительный просмотр остается точно там, где он есть, в то время как остальная часть интерфейса поворачивается, чтобы выровняться с ориентацией.
Единственный способ, которым я работал в iOS 8–11.1 без каких-либо проблем, - это сделать это, и я должен отметить, что в моем случае я загрузил свое приложение только в ландшафтном режиме, но оно должно работать во всех ориентациях.(Кстати, вы можете наложить камера вручную через imageview или что-нибудь, что вы хотите очень легко)
@interface ViewController (){
AVCaptureVideoPreviewLayer * previewLayer;
AVCaptureSession* session;
}
@property (weak, nonatomic) IBOutlet UIView *cameraPreviewView;
-(void)viewDidLoad{
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
if (captureInput) {
session = [[AVCaptureSession alloc] init];
[session addInput:captureInput];
}
previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
[previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
CALayer *rootLayer = [self.cameraPreviewView layer];
[rootLayer setMasksToBounds:YES];
[previewLayer setFrame:[self.view bounds]];
[rootLayer addSublayer:previewLayer];
[session startRunning];
//Orientation Code is in viewDidLayoutSubviews method
}
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
switch (orientation) {
case UIInterfaceOrientationPortrait:
[previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
break;
case UIInterfaceOrientationPortraitUpsideDown:
[previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
break;
case UIInterfaceOrientationLandscapeLeft:
[previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
break;
case UIInterfaceOrientationLandscapeRight:
[previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
break;
default:break;
}
}