swi*_*itz 8 uiviewcontroller autorotate ios swift
我有一个带有子视图控制器的视图控制器.
tab bar controller
|
|
nav controller
|
|
UIPageViewController (should rotate)
|
|
A (Video Player) (shouldn't rotate)
|
|
B (Controls overlay) (should rotate)
Run Code Online (Sandbox Code Playgroud)
应该强制A始终保持纵向,但应允许B自由旋转.
我知道shouldAutorotate适用于任何视图控制器及其子级,但有没有办法解决这个问题?好像我可以使用shouldAutorotateToInterfaceOrientation,但这在iOS 8中被阻止了.
我想保持视频播放器静态(因此水平视频始终是水平的,无论设备方向如何),而控制层子视图覆盖允许自由旋转.
我正在使用Swift.
jst*_*stn 19
我有这个确切的问题,很快发现有很多关于自动旋转的坏建议,特别是因为iOS 8处理它与以前的版本不同.
首先,您不希望手动应用反向UIDevice旋转或订阅方向更改.执行反旋转仍会导致难看的动画,并且设备方向并不总是与界面方向相同.理想情况下,您希望相机预览保持真正冻结状态,并使您的应用UI与状态栏方向和大小相匹配,就像本机相机应用程序一样.
在iOS 8中进行方向更改期间,窗口本身会旋转而不是它包含的视图.您可以将多个视图控制器的视图添加到单个视图中UIWindow,但只有rootViewController会有机会通过响应shouldAutorotate().即使您在视图控制器级别进行旋转决策,它也是实际旋转的父窗口,从而旋转其所有子视图(包括来自其他视图控制器的子视图).
解决方案是两个UIWindow堆叠在彼此之上,每个解决方案都使用自己的根视图控制器旋转(或不旋转).大多数应用只有一个,但没有理由你不能有两个,并像其他UIView子类一样覆盖它们.
这是一个工作概念验证,我也在这里放了GitHub.你的特殊情况有点复杂,因为你有一堆包含视图控制器,但基本思路是一样的.我将在下面谈谈一些具体问题.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var cameraWindow: UIWindow!
var interfaceWindow: UIWindow!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
let screenBounds = UIScreen.mainScreen().bounds
let inset: CGFloat = fabs(screenBounds.width - screenBounds.height)
cameraWindow = UIWindow(frame: screenBounds)
cameraWindow.rootViewController = CameraViewController()
cameraWindow.backgroundColor = UIColor.blackColor()
cameraWindow.hidden = false
interfaceWindow = UIWindow(frame: CGRectInset(screenBounds, -inset, -inset))
interfaceWindow.rootViewController = InterfaceViewController()
interfaceWindow.backgroundColor = UIColor.clearColor()
interfaceWindow.opaque = false
interfaceWindow.makeKeyAndVisible()
return true
}
}
Run Code Online (Sandbox Code Playgroud)
设置负插入interfaceWindow使其略大于屏幕边界,有效地隐藏了您将看到的黑色矩形蒙版.通常您不会注意到,因为蒙版随窗口一起旋转,但由于相机窗口已固定,因此在旋转过程中,蒙版在角落中变得可见.
class CameraViewController: UIViewController {
override func shouldAutorotate() -> Bool {
return false
}
}
Run Code Online (Sandbox Code Playgroud)
正是您所期望的,只需添加您自己的设置AVCapturePreviewLayer.
class InterfaceViewController: UIViewController {
var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
contentView = UIView(frame: CGRectZero)
contentView.backgroundColor = UIColor.clearColor()
contentView.opaque = false
view.backgroundColor = UIColor.clearColor()
view.opaque = false
view.addSubview(contentView)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let screenBounds = UIScreen.mainScreen().bounds
let offset: CGFloat = fabs(screenBounds.width - screenBounds.height)
view.frame = CGRectOffset(view.bounds, offset, offset)
contentView.frame = view.bounds
}
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
override func shouldAutorotate() -> Bool {
return true
}
}
Run Code Online (Sandbox Code Playgroud)
最后一个技巧是撤消我们应用于窗口的负插入,我们通过偏移view相同的数量并将其contentView视为主视图来实现.
对于您的应用程序,interfaceWindow.rootViewController将是您的标签栏控制器,它又包含一个导航控制器等.当您的相机控制器出现时,所有这些视图都需要透明,以便相机窗口可以在其下方显示.出于性能原因,您可能会考虑将它们保持不透明状态,并且仅在实际使用相机时将所有内容设置为透明,并将相机窗口设置为hidden不适用时(同时还关闭捕获会话).
抱歉发布一本小说; 我还没有在其他任何地方看到这个问题,我花了一段时间才弄明白,希望它可以帮助你和其他任何试图获得相同行为的人.即使是Apple的AVCam示例应用程序也不能正确处理它.
我发布的示例repo还包括已经设置了相机的版本.祝好运!
| 归档时间: |
|
| 查看次数: |
4334 次 |
| 最近记录: |