Since iOS 8.0, the function didRotateFromInterfaceOrientation
becomes deprecated and I now have no idea how to change the orientation of AVCaptureVideoPreviewLayer properly.
According to "interfaceOrientation" is deprecated in iOS 8, How to change this method Objective C, I have the following working code to get the AVCaptureVideoOrientation
based on statusBarOrientation
:
- (AVCaptureVideoOrientation)getOrientation {
// Translate the orientation
switch ([[UIApplication sharedApplication] statusBarOrientation]) {
case UIInterfaceOrientationPortrait:
return AVCaptureVideoOrientationPortrait;
case UIInterfaceOrientationPortraitUpsideDown:
return AVCaptureVideoOrientationPortraitUpsideDown;
case UIInterfaceOrientationLandscapeLeft:
return AVCaptureVideoOrientationLandscapeLeft;
case UIInterfaceOrientationLandscapeRight:
return AVCaptureVideoOrientationLandscapeRight;
default:
return AVCaptureVideoOrientationPortrait;
}
}
I need to call this following function when the orientation is changed:
[self.videoPreviewLayer.connection setVideoOrientation:[self getOrientation]];
But I don't know where is the right place to put it.
Since didRotateFromInterfaceOrientation
is deprecated and Apple suggest to use viewWillTransitionToSize:withTransitionCoordinator:
, this seems natural to try:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self.videoPreviewLayer.connection setVideoOrientation:[self getOrientation]];
}];
}
But this function doesn't get called if the UIViewController
is being presented (seems to be a known bug based on "viewWillTransitionToSize:" not called in iOS 9 when the view controller is presented modally). Even if this bug is resolved, there is another problem: orientation change is not equivalent to size change. For instance, if a view is presented with UIModalPresentationFormSheet
as the following,
SecondViewController *vc = [[SecondViewController alloc] init];
vc.view.backgroundColor = [UIColor greenColor];
vc.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:vc animated:true completion:nil];
the presented view size the same under landscape and portrait mode for iPad:
Therefore, I cannot simply use viewWillTransitionToSize
.
I notice that UIDeviceOrientationDidChangeNotification
is not deprecated. Great! I tried register a notification with that:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Some other code to set up the preview layer
// ...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deviceOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)deviceOrientationDidChange:(NSNotification *)notification {
[self.videoPreviewLayer.connection setVideoOrientation:[self getOrientation]];
}
This is almost working and it is so closed! The problem is that when I get the device orientation changed notification, the animation of rotating the view maybe started and maybe not. Or in another word, the return value [[UIApplication sharedApplication] statusBarOrientation]
may be incorrect if the device is already rotated up side down but the animation is still pending.
And I don't know what else to try :( Any ideas?
The following should be able to handle orientation of video preview properly in swift 2.1:
override func viewWillAppear(animated: Bool) {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("deviceOrientationDidChange:"),
name: UIDeviceOrientationDidChangeNotification,
object: nil)
}
override func viewDidDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self)
super.viewDidDisappear(animated)
}
func deviceOrientationDidChange(sender: AnyObject) {
let deviceOrientation = UIDevice.currentDevice().orientation;
switch (deviceOrientation)
{
case .Portrait:
previewLayer.connection.videoOrientation = .Portrait
case .LandscapeLeft:
previewLayer.connection.videoOrientation = .LandscapeRight
case .LandscapeRight:
previewLayer.connection.videoOrientation = .LandscapeLeft
case .PortraitUpsideDown:
previewLayer.connection.videoOrientation = .PortraitUpsideDown
default:
break
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With