2014-01-21 1 views
12

Как я могу получить «AVCaptureVideoPreviewLayer» для правильной отображения в альбомной ориентации? Он отлично работает в портрете, но не вращается и показывает повернутый захват камеры, когда контроллер родительского представления находится в альбомной ориентации.AVCaptureVideoPreviewLayer ландшафтная ориентация

ответ

29

Во-первых, ответ

- (void)viewWillLayoutSubviews { 
    _captureVideoPreviewLayer.frame = self.view.bounds; 
    if (_captureVideoPreviewLayer.connection.supportsVideoOrientation) { 
    _captureVideoPreviewLayer.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; 
} 

Я пришел через несколько С.О. сообщений по этому вопросу, и не мог найти простое объяснение, так что я думал, что я хотел бы поделиться моим собственным.

Если вы будете следовать образцу компании Apple по этому вопросу, вы будете работать в двух возможных проблемы при повороте устройства IOS на альбомную

  1. Захват будет казаться повернутым (как будто вы держите камеру на 90 градусов выкл)
  2. это не будет занимать свои установленные границы полностью

проблема здесь состоит в том, что «CALayer» не поддерживает авторотации, следовательно, в отличие от «UIView» вы бы добавить, как подвид, он выиграл 't вращается, когда его родительский «UIView» вращается. Поэтому вам необходимо вручную обновлять свой фрейм каждый раз, когда границы родительского представления изменяются (не кадр родительского представления, так как кадр остается неизменным после поворота). Это достигается за счет переопределения 'viewWillLayoutSubviews' в контроллере контейнера.

Во-вторых, вы должны использовать свойство videoOrientation, чтобы информировать AVFoundation о ориентации, чтобы он правильно просматривал.

Надеюсь, это поможет.

+0

Override viewWillLayoutSubviews() решить мою проблему! Благодарю. – iForests

+0

Отлично! Но мне пришлось реализовать will- or didRotateToInterfaceOrientation() с вызовом self.view.setNeedsLayout(), чтобы получить viewWillLayoutSubviews, называемый –

+0

Этот метод помог мне безмерно. Спасибо mate –

0

Помимо viewWillLayoutSubviews(), вам также необходимо реализовать didRotateFromInterfaceOrientation().

Это связано с тем, что макеты subview не будут обновляться, если устройство поворачивается с портретного режима на портретный перевернутый режим (очевидно, по соображениям эффективности).

2
override func viewWillLayoutSubviews() { 
    self.previewLayer.frame = self.view.bounds 
    if previewLayer.connection.isVideoOrientationSupported { 
     self.previewLayer.connection.videoOrientation = self.interfaceOrientation(toVideoOrientation: UIApplication.shared.statusBarOrientation) 
    } 
} 

func interfaceOrientation(toVideoOrientation orientation: UIInterfaceOrientation) -> AVCaptureVideoOrientation { 
    switch orientation { 
    case .portrait: 
     return .portrait 
    case .portraitUpsideDown: 
     return .portraitUpsideDown 
    case .landscapeLeft: 
     return .landscapeLeft 
    case .landscapeRight: 
     return .landscapeRight 
    default: 
     break 
    } 

    print("Warning - Didn't recognise interface orientation (\(orientation))") 
    return .portrait 
} 

// СВИФТ 3 Конверсия

+0

Это отлично работает _except_ в тех случаях, когда камера не отображается и не запускается viewDidLoad(), которая вводит всевозможные проблемы, потому что предварительный слой может еще не существовать. Из-за этого ответ @neoneye выше следует считать правильным. –

6

Swift3

func updateVideoOrientation() { 
    guard let previewLayer = self.previewLayer else { 
     return 
    } 
    guard previewLayer.connection.isVideoOrientationSupported else { 
     print("isVideoOrientationSupported is false") 
     return 
    } 

    let statusBarOrientation = UIApplication.shared.statusBarOrientation 
    let videoOrientation: AVCaptureVideoOrientation = statusBarOrientation.videoOrientation ?? .portrait 

    if previewLayer.connection.videoOrientation == videoOrientation { 
     print("no change to videoOrientation") 
     return 
    } 

    previewLayer.frame = cameraView.bounds 
    previewLayer.connection.videoOrientation = videoOrientation 
    previewLayer.removeAllAnimations() 
} 

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransition(to: size, with: coordinator) 

    coordinator.animate(alongsideTransition: nil, completion: { [weak self] (context) in 
     DispatchQueue.main.async(execute: { 
      self?.updateVideoOrientation() 
     }) 
    }) 
} 

extension UIInterfaceOrientation { 
    var videoOrientation: AVCaptureVideoOrientation? { 
     switch self { 
     case .portraitUpsideDown: return .portraitUpsideDown 
     case .landscapeRight: return .landscapeRight 
     case .landscapeLeft: return .landscapeLeft 
     case .portrait: return .portrait 
     default: return nil 
     } 
    } 
} 
+0

Отлично. **Благодаря!** –