Как я могу получить «AVCaptureVideoPreviewLayer» для правильной отображения в альбомной ориентации? Он отлично работает в портрете, но не вращается и показывает повернутый захват камеры, когда контроллер родительского представления находится в альбомной ориентации.AVCaptureVideoPreviewLayer ландшафтная ориентация
ответ
Во-первых, ответ
- (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 на альбомную
- Захват будет казаться повернутым (как будто вы держите камеру на 90 градусов выкл)
- это не будет занимать свои установленные границы полностью
проблема здесь состоит в том, что «CALayer» не поддерживает авторотации, следовательно, в отличие от «UIView» вы бы добавить, как подвид, он выиграл 't вращается, когда его родительский «UIView» вращается. Поэтому вам необходимо вручную обновлять свой фрейм каждый раз, когда границы родительского представления изменяются (не кадр родительского представления, так как кадр остается неизменным после поворота). Это достигается за счет переопределения 'viewWillLayoutSubviews' в контроллере контейнера.
Во-вторых, вы должны использовать свойство videoOrientation, чтобы информировать AVFoundation о ориентации, чтобы он правильно просматривал.
Надеюсь, это поможет.
Помимо viewWillLayoutSubviews(), вам также необходимо реализовать didRotateFromInterfaceOrientation().
Это связано с тем, что макеты subview не будут обновляться, если устройство поворачивается с портретного режима на портретный перевернутый режим (очевидно, по соображениям эффективности).
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 Конверсия
Это отлично работает _except_ в тех случаях, когда камера не отображается и не запускается viewDidLoad(), которая вводит всевозможные проблемы, потому что предварительный слой может еще не существовать. Из-за этого ответ @neoneye выше следует считать правильным. –
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 viewWillLayoutSubviews() решить мою проблему! Благодарю. – iForests
Отлично! Но мне пришлось реализовать will- or didRotateToInterfaceOrientation() с вызовом self.view.setNeedsLayout(), чтобы получить viewWillLayoutSubviews, называемый –
Этот метод помог мне безмерно. Спасибо mate –