Ландшафтная ориентация AVCaptureVideoPreviewLayer
Как я могу получить "AVCaptureVideoPreviewLayer" для правильного отображения в альбомной ориентации? Он отлично работает в портрете, но не вращается и показывает поворот камеры, когда контроллер родительского вида находится в альбомной ориентации.
4 ответов
во-первых, ответ
- (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;
}
я наткнулся на несколько сообщений SO по этому вопросу и не мог найти простого объяснения, поэтому я подумал, что поделюсь своим собственным.
Если вы последуете примеру Apple по этому вопросу, вы столкнетесь с двумя потенциальными проблемами при повороте устройства iOS в landscape
- захват появится повернутым (как будто вы держите камеру на 90 градусов)
- он не будет охватывать установленные границы полностью
проблема здесь в том, что "CALayer" не поддерживает авторотацию, поэтому, в отличие от "UIView", который вы добавляете в качестве подвида, он не будет вращаться, когда его Родительский "UIView" вращается. Поэтому вы должны вручную обновлять его кадр каждый раз, когда границы родительского представления изменяются (не кадр родительского вида, так как кадр остается неизменным после вращения). Это достигается путем переопределения "viewWillLayoutSubviews" в контроллере представления контейнера.
во-вторых, вы следует использовать свойство videoOrientation для информирования AVFoundation об ориентации, чтобы он правильно выполнял предварительный просмотр.
надеюсь, что это помогает.
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
}
}
}
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
}
/ / SWIFT 3 ПРЕОБРАЗОВАНИЕ
помимо viewWillLayoutSubviews (), вам также необходимо реализовать didRotateFromInterfaceOrientation ().
Это потому, что макеты подвида не будут обновлены, если устройство вращается из портретного режима в портретный перевернутый режим (очевидно, по соображениям эффективности).