我的应用程序支持除PortraitUpsideDown之外的所有方向。 在我的视图层次结构中,我有一个AVCaptureVideoPreviewLayer作为顶视图中的子图层,即UIImageView。然后在视图层次结构下面是几个显示控件的叠加视图。
叠加视图在方向更改时正常工作,但我不知道如何使用此AVCaptureVideoPreviewLayer。我希望它的行为类似于Camera应用程序,以便previewLayer保持静止并且控件可以平滑地重新组织。现在,由于主视图在方向更改时旋转,我的预览图层也会旋转,这意味着在横向视图中它保持纵向视图,仅占用屏幕的一部分,相机的图片也旋转90度。我已设法手动旋转预览图层,但之后它有这个方向更改动画,这导致在动画期间看到背景一段时间。
那么在使previewLayer保持静止的同时自动旋转控件的正确方法是什么?
答案 0 :(得分:5)
在我的实现中,我已经将UIView子类化为我想要旋转的视图,以及类似于此视图的viewController,它只是NSObject的子类。
在这个viewController中,我做了与方向变化相关的所有检查,如果我应该改变目标视图的方向,做出决定,如果是,那么我调用我的视图方法来改变方向。
首先,我们需要将整个应用程序界面的方向修改为纵向模式,以便我们的ACCaptureVideoPreviewLayer始终保持静止。
这是在MainViewController.h
:
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation`
{
return interfaceOrientation==UIInterfaceOrientationPortrait;
}
除了肖像之外,它向所有方向返回NO。
为了让我们的自定义viewController能够跟踪设备方向的变化,我们需要让它成为相应通知的观察者:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
我将这些行放在viewController的(void)awakeFromNib
方法中。
因此,每次更改设备方向时,都会调用viewController的方法orientationChanged
。
其目的是检查设备的新方向是什么,设备的最后方向是什么,并决定是否更改它。以下是实施:
if(UIInterfaceOrientationPortraitUpsideDown==[UIDevice currentDevice].orientation ||
lastOrientation==(UIInterfaceOrientation)[UIDevice currentDevice].orientation)
return;
[[UIApplication sharedApplication]setStatusBarOrientation:[UIDevice currentDevice].orientation animated:NO];
lastOrientation=[UIApplication sharedApplication].statusBarOrientation;
[resultView orientationChanged];
如果方向与之前相同或在PortraitUpsideDown中,则不执行任何操作。 否则,它会将状态栏方向设置为正确的方向,以便在有来电或骨化时,它将显示在屏幕的正确一侧。然后我在目标视图中调用also方法,其中完成了新方向的所有相应更改,例如旋转,调整大小,在此视图中移动与新方向对应的界面的其他元素。
以下是目标视图中orientationChanged
的实现:
Float32 angle=0.f;
UIInterfaceOrientation orientation=[UIApplication sharedApplication].statusBarOrientation;
switch (orientation) {
case UIInterfaceOrientationLandscapeLeft:
angle=-90.f*M_PI/180.f;
break;
case UIInterfaceOrientationLandscapeRight:
angle=90.f*M_PI/180.f;
break;
default: angle=0.f;
break;
}
if(angle==0 && CGAffineTransformIsIdentity(self.transform)) return;
CGAffineTransform transform=CGAffineTransformMakeRotation(angle);
[UIView beginAnimations:@"rotateView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.35f];
self.transform=transform;
[UIView commitAnimations];
当然,您可以添加任何其他更改,例如翻译,缩放界面的不同视图,这些视图需要响应新的方向并为其设置动画。
此外,您可能不需要viewController,但只需在视图的类中执行。 希望总体思路清晰。
另外,当您不需要时,不要忘记停止获取方向更改通知:
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications];
答案 1 :(得分:1)
iOS 8解决方案:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
} else {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
}
在您的设置代码中:
self.layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
} else {
self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
答案 2 :(得分:0)
主要问题是当我收到通知时,状态栏尚未旋转,因此检查当前值实际上是旋转前的值。所以我在调用检查statusbarorientation并旋转我的子视图的方法之前添加了一点延迟(这里是2秒):
-(void) handleNotification:(NSNotification *) notification
{
(void) [NSTimer scheduledTimerWithTimeInterval:(2.0)
target:self
selector:@selector(orientationChanged)
userInfo:nil
repeats:NO ] ;
}
其余代码是BartoNaz的代码。