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

要旋转的子视图控制器,而父视图控制器不旋转

王昆
2023-03-14

我想做的是:

由父视图控制器管理的父视图不应旋转。

由子视图控制器管理的子视图应该旋转到所有方向。

我所尝试的:

家长视图控制器

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return .Portrait
}

override func shouldAutorotate() -> Bool {
    return true
}

fun addChildViewController() {
    let storyBoard = UIStoryboard(name: "Main", bundle: nil)
    self.childViewController = storyBoard("Child View Controller") as? ChildViewController
    self .addChildViewController(self.childViewController!)
    self.childViewController! .didMoveToParentViewController(self)
    self.view .addSubview(self.childViewController!.view)
    self.childViewController!.view.frame = CGRectMake (40, 200, 400, 250)
}

儿童视图控制器

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return  .All
}

override func shouldAutorotate() -> Bool {
    return true
}

Xcode部署信息中支持的方向设置为所有四个。

我得到的:

没有视图的旋转。如果将父视图的旋转设置为“全部”,则所有视图将一起旋转。所以要么全有要么全无。

更新

当我尝试放置UIDeviceOrientationIDChangeNotification的观察者并使用UIDevice时。currentDevice()。方向旋转子视图使用CGAffaineTransformMakeRotate,我得到了想要的结果。但是,也就是说,如果我旋转到横向,并尝试拉下通知中心(或者如果我收到系统通知),通知中心仍处于纵向(因为应用程序本机仍处于纵向),旋转后的儿童视图将旋转回纵向,以符合状态栏/通知/通知中心的要求。

Stock iOS Camera应用程序是我能展示的最好的例子。主画布不会旋转到不同的方向,但状态栏在幕后会旋转以支持设备旋转。此外,子视图本身也会在其中旋转,以适应不同的方向。我正在努力实现这一行为。。。。

共有3个答案

孟凯泽
2023-03-14

经过多次来回与苹果他们自己,他们指向同一个链接技术Q

MotherViewController

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

        coordinator.animateAlongsideTransition({(context: UIViewControllerTransitionCoordinatorContext) -> Void in
            let deltaTransform: CGAffineTransform = coordinator.targetTransform()
            let deltaAngle: CGFloat = atan2(deltaTransform.b, deltaTransform.a)
            var currentRotation: CGFloat = self.mainView.layer.valueForKeyPath("transform.rotation.z") as! CGFloat

            // Adding a small value to the rotation angle forces the animation to occur in a the desired direction, preventing an issue where the view would appear to rotate 2PI radians during a rotation from LandscapeRight -> LandscapeLeft.
            currentRotation += -1 * deltaAngle + 0.0001
            self.mainView.layer.setValue(currentRotation, forKeyPath: "transform.rotation.z")

            }, completion: {(
                context: UIViewControllerTransitionCoordinatorContext) -> Void in
                // Integralize the transform to undo the extra 0.0001 added to the rotation angle.
                var currentTransform: CGAffineTransform = self.mainView.transform
                currentTransform.a = round(currentTransform.a)
                currentTransform.b = round(currentTransform.b)
                currentTransform.c = round(currentTransform.c)
                currentTransform.d = round(currentTransform.d)
                self.mainView.transform = currentTransform
        })
    }

主视图控制

NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name:UIDeviceOrientationDidChangeNotification, object: nil)

func orientationChanged ( notification: NSNotification){
        switch UIDevice.currentDevice().orientation {
        case .Portrait:
            self.rotateChildViewsForOrientation(0)
        case .PortraitUpsideDown:
            self.rotateChildViewsForOrientation(0)
        case .LandscapeLeft:
            self.rotateChildViewsForOrientation(90)
        case .LandscapeRight:
            self.rotateChildViewsForOrientation(-90)
        default:
            print ("Default")
                }
    }

这似乎会旋转子视图,同时保持主视图静态。此外,当通知进来时,应用程序似乎知道正确的方向(因为母视图实际上在幕后旋转)。

特别感谢jamesk和Warif Akhand Rishi的帮助!

吴展
2023-03-14

来自iOS开发者库技术Q

当系统确定接口必须旋转时,通过对应用程序的窗口应用旋转变换来实现自动旋转。然后,窗口为新方向调整其边界,并通过调用每个视图控制器和表示控制器的-viewWillTranstionToSize: with Trantion协调器:方法将此更改向下传播到视图控制器层次结构。此方法的调用提供了一个过渡协调器对象,其中包含窗口当前变换和新变换的增量,可以通过向过渡协调器发送-Target etTransform消息来检索。您的视图控制器或表示控制器可以派生适当的逆变换并将其应用于目标视图。这抵消了窗口变换对该特定视图的影响,并给出了当界面的其余部分正常旋转时,视图在其当前方向上保持固定的外观。

i、 e.如果您有一个名为noRotatingView的视图

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    noRotatingView.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds))
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition({ (UIViewControllerTransitionCoordinatorContext) -> Void in

        let deltaTransform = coordinator.targetTransform()
        let deltaAngle = atan2f(Float(deltaTransform.b), Float(deltaTransform.a))

        var currentRotation = self.noRotatingView.layer.valueForKeyPath("transform.rotation.z")?.floatValue

        // Adding a small value to the rotation angle forces the animation to occur in a the desired direction, preventing an issue where the view would appear to rotate 2PI radians during a rotation from LandscapeRight -> LandscapeLeft.
        currentRotation = currentRotation! + (-1 * Float(deltaAngle)) + 0.0001
        self.noRotatingView.layer.setValue(currentRotation, forKeyPath:"transform.rotation.z")

        }) { (UIViewControllerTransitionCoordinatorContext) -> Void in

            var currentTransform = self.noRotatingView.transform;
            currentTransform.a = round(currentTransform.a);
            currentTransform.b = round(currentTransform.b);
            currentTransform.c = round(currentTransform.c);
            currentTransform.d = round(currentTransform.d);
            self.noRotatingView.transform = currentTransform;
    }
}

我试着在https://github.com/rishi420/TestCameraRotation

龙星渊
2023-03-14

在相机应用程序中实现的效果类似于使用以下组合:

  • 技术Q中描述的技术

技术说明解释了自动旋转的底层实现涉及将转换直接应用于应用程序的窗口:

当系统确定接口必须旋转时,通过对应用程序窗口应用旋转变换来实现自动旋转。然后,窗口调整其新方向的边界,并通过调用每个视图控制器和表示控制器的viewWillTransitionToSize:withTransitionCoordinator:方法,通过视图控制器层次结构向下传播此更改。

请注意,摄像头应用程序不会选择退出自动旋转:使用摄像头应用程序时,通知中心和控制中心的方向反映设备方向。只有相机应用程序中的特定视图才会选择退出自动旋转。事实上,这个答案表明,这类应用程序通常使用AVFoundation类(如AVCaptureVideoPreviewLayer和AVCaptureConnection)提供的videoGravity和videoOrientation属性。

您应该采取的方法取决于您是只想阻止父视图旋转,还是想阻止容器视图控制器(如UINavigationController)旋转(即锁定设备方向)。

如果是前者,请使用技术说明中描述的技术来固定父视图的方向,并且(对于iOS 9)在UIStackView中包裹旋转子视图,并使用轴属性来重新排列设备旋转时的子视图,或者(对于iOS 8)在设备旋转时手动旋转子视图(参见此答案和示例代码)。

如果是后者,则您正在采取的方法是正确的。有关示例代码,请参阅此答案。您需要共享您的代码和有关视图控制器层次结构的更多信息,以便我们诊断涉及通知中心的怪癖。

附录:技术Q中解释了为什么对的调用应该Autorotate支持InterfaceOrientations没有传播到子视图控制器的原因

从iOS6开始,只有最顶层的视图控制器(与UIApplication对象一起)参与决定是否旋转以响应设备方向的更改。通常情况下,显示您的内容的视图控制器是UINavigationControllerUITabBarController或自定义容器视图控制器的子类。您可能会发现自己需要子类化容器视图控制器以修改其支持的InterfaceOrientations应自动旋转方法返回的值。

在Swift中,您可以使用扩展覆盖这些方法。

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

  • 我有一个带有子视图控制器的视图控制器。 应强制A始终保持纵向,但应允许B自由旋转。 我知道shouldAutorotate应该适用于任何视图控制器及其子级,但有什么方法可以绕过它吗?看起来我可以使用shouldAutorotateToInterfaceOrientation,但这在iOS 8中被阻止了。 我想保持视频播放器静态(因此无论设备方向如何,水平视频始终是水平的),而控制层子视图覆盖允许自

  • 以下的一段代码相当于定义一个ParameterizableViewController视图控制器的快捷方式,该控制器会立即将一个请求转发(forwards)给一个视图。请确保仅在以下情景下才使用这个类:当控制器除了将视图渲染到响应中外不需要执行任何逻辑时。 以下是一个例子,展示了如何在MVC Java编程配置方式下将所有"/"请求直接转发给名字为"home"的视图: @Configuration

  • 我找到了一些关于这个问题的帖子,但是没有一个能解决我的问题。 说像我已经... ViewControlllerA ViewControlllerB 我试图将ViewControlllerB添加为ViewControlllerA中的子视图,但是,它抛出了一个错误,如""。 下面是代码。。。 视图控制器 ViewControllerB只是一个带有标签的简单屏幕。 视图控制器B 编辑

  • 问题内容: 我没有找到有关此问题的文章,但没有一个解决我的问题。 就像我说的那样。 ViewControllerA ViewControllerB 我试图将添加为的子视图,但是它 抛出类似“ ” 的错误。 下面是代码… ViewControllerA ViewControllerB只是一个带有标签的简单屏幕。 ViewControllerB EDIT 根据用户答案的​​建议解决方案,ViewCon

  • 问题内容: 我为其中一个页面设置了一个版式,然后使用大量的小视图作为种子,这些小视图用于填充日期。我的状态目前看起来像这样: 如您所见,父布局将我的Controller保留在称为 EventCtrl 的页面上。现在,我希望所有视图现在都可以访问此控制器,但事实并非如此。相反,我必须将来自 eventLayout 的主要父模板包装到div中,然后在其中使用旧学校: 我至少想了解为什么会发生这种情况,