当前位置: 首页 > 知识库问答 >
问题:

强制iOS视图不旋转,同时仍允许子视图旋转

柳珂
2023-03-14

我有一个带有子视图控制器的视图控制器。

tab bar controller
|
|
nav controller
|
|
UIPageViewController (should rotate)
|
|
A (Video Player) (shouldn't rotate)
|
|
B (Controls overlay) (should rotate)

应强制A始终保持纵向,但应允许B自由旋转。

我知道shouldAutorotate应该适用于任何视图控制器及其子级,但有什么方法可以绕过它吗?看起来我可以使用shouldAutorotateToInterfaceOrientation,但这在iOS 8中被阻止了。

我想保持视频播放器静态(因此无论设备方向如何,水平视频始终是水平的),而控制层子视图覆盖允许自由旋转。

我用的是Swift。

共有3个答案

强阳曜
2023-03-14

您可以订阅旋转更改通知,并在要旋转的子视图上手动设置旋转变换矩阵。

耿永寿
2023-03-14

你可以试试这个-

Objective-C代码,如果您在swift中有它的替代方案:

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
   if ()//Place your condition here like if A is visible
   {
     return UIInterfaceOrientationMaskPortrait;
   }
     return UIInterfaceOrientationMaskAll;
} 
袁泰
2023-03-14

我遇到了这个问题,很快就发现有很多关于自动旋转的错误建议,特别是因为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
    }
}

在界面窗口(interfaceWindow)上设置一个负片插入,使其略大于屏幕边界,有效地隐藏了您在其他情况下看到的黑色矩形遮罩。通常,您不会注意到,因为遮罩会随窗口旋转,但由于相机窗口是固定的,因此在旋转过程中,遮罩会在拐角处可见。

class CameraViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

正如您在这里所期望的,只需为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
    }
}

最后一个技巧是撤消应用于窗口的负插入,我们通过偏移相同的量并将内容视图作为主视图来实现。

对于您的应用程序,interface窗口。rootViewController将是您的选项卡栏控制器,它又包含一个导航控制器等。当您的相机控制器出现时,所有这些视图都需要透明,以便相机窗口可以在其下方显示。出于性能原因,您可能会考虑让它们保持不透明,并且只在相机实际使用时将所有内容设置为透明,而在不使用时将相机窗口设置为hidden(同时关闭捕获会话)。

抱歉发布小说;我在其他任何地方都没有看到这个地址,我花了一段时间才弄清楚,希望它能帮助您和其他试图获得相同行为的人。即使是Apple的AVCam示例应用程序也不能很好地处理它。

我发布的示例repo还包括一个已经安装了摄像头的版本。祝你好运

 类似资料:
  • 我想做的是: 由父视图控制器管理的父视图不应旋转。 由子视图控制器管理的子视图应该旋转到所有方向。 我所尝试的: 家长视图控制器 儿童视图控制器 Xcode部署信息中支持的方向设置为所有四个。 我得到的: 没有视图的旋转。如果将父视图的旋转设置为“全部”,则所有视图将一起旋转。所以要么全有要么全无。 更新 当我尝试放置UIDeviceOrientationIDChangeNotification的

  • 我正在开发一款ios应用程序,它必须在横向和纵向两种模式下都能工作,但有一种视图应该始终在横向模式下。因此,我有: 如果我在横向模式下使用我的应用程序,并到达此视图并旋转设备(iPad),则调用此方法并返回false,因此界面不会旋转,好东西。 但是如果我在纵向视图中,并且到达该视图,则调用此方法并返回false,但是方向不会改变。在这种情况下,如果我将设备旋转到横向,该方法将返回true,接口将

  • 我有一个iPhone应用程序,它使用一个UINavigationController来呈现一个深入的界面:首先是一个视图,然后是另一个视图,最多四层。我希望前三个视图限制为纵向,并且只允许最后一个视图旋转为横向。当从第四个视图返回到第三个视图时,第四个视图是横向的,我希望所有的东西都旋转回纵向。 在iOS5中,我简单地在我的每个视图控制器中定义了以返回YES作为允许的方向。一切都如上所述工作,包括

  • 我正在尝试将子视图控制器添加到父视图控制器,并让父视图控制器通知子视图控制器旋转事件。但是,旋转消息不会转发到子视图控制器(这是默认行为)。为什么没有发生这种默认行为? 环境:iOS 7、XCode 5、OSX 10.9 我正在按照Apple文档中的说明实现一个自定义容器视图控制器:“创建自定义容器视图控制器”。我试图建立一个简单的父子关系来转发旋转事件。总体层次结构与此处重新绘制的文档图14-1

  • 我有一个聊天应用程序,可以打开一个到服务器的Websocket。该应用程序有2个模块- chat sdk:处理连接和来回消息传递。 用户界面:处理适配器和视图 聊天UI位于活动托管的片段上。 一切都很好,但当我决定在设备旋转上使用持久性时,我遇到了问题。当我旋转设备时,websocket重新连接(这是正常的),活动被重新创建,片段也被重新创建。 经过设备旋转和一些调试,我看到我的消息列表被正确填充

  • 问题内容: 我想找出悬停时如何制作 旋转或旋转的图像 。我想知道如何在以下代码上使用 CSS 模仿该功能: 问题答案: 您可以将CSS3过渡与一起使用,以 在悬停时旋转图像 。 旋转图像: