首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >要旋转的子视图控制器,而父视图控制器不旋转

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

Stack Overflow用户
提问于 2016-07-31 22:28:55
回答 3查看 7.8K关注 0票数 26

我正在尝试做的事情:

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

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

我尝试过的东西:

ParentViewController

代码语言:javascript
复制
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)
}

ChildViewController

代码语言:javascript
复制
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return  .All
}

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

Xcode Deployment Info中支持的方向设置为全部四个。

我得到了什么:

视图都不旋转。如果我将父视图的旋转设置为all,则所有视图都会一起旋转。所以要么全有要么什么都没有。

更新

当我尝试为UIDeviceOrientationDidChangeNotification放置一个观察者,并使用UIDevice.currentDevice().orientation使用CGAffaineTransformMakeRotate旋转childView时,我得到了想要的结果。然而,如果我旋转到横向,并试图拉下通知中心(或者如果我收到系统通知),它仍然是纵向的(因为应用程序本身仍然留在纵向),旋转的childView会旋转回纵向以尊重状态栏/通知/通知中心。

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-08-16 23:56:16

在多次与苹果公司来回交流之后,他们指向了同一个链接Technical Q&A QA1890,我不得不用流畅的方式来做这件事:

MotherViewController

代码语言:javascript
复制
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
        })
    }

MainViewController

代码语言:javascript
复制
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")
                }
    }

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

特别感谢jameskWarif Akhand 的所有帮助!

票数 2
EN

Stack Overflow用户

发布于 2016-08-10 21:30:27

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

中所示的AdaptiveElements示例代码中的SimpleExampleViewController

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

当系统确定界面必须旋转时,通过对应用程序的窗口应用旋转转换来实现

自动旋转。然后,该窗口针对新的方向调整其边界,并通过调用每个视图控制器和表示控制器的viewWillTransitionToSize:withTransitionCoordinator:方法,在视图控制器层次结构中向下传播此更改。

请注意,相机应用程序无法退出自动旋转:使用相机应用程序时,通知中心和控制中心的方向会反映设备的方向。只有相机应用程序中的特定视图似乎才会选择退出自动旋转。事实上,this answer建议这类应用程序通常利用AVCaptureVideoPreviewLayerAVCaptureConnection等AVFoundation类提供的videoGravityvideoOrientation属性。

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

如果是前者,请使用技术说明中描述的技术来确定父视图的方向,并(对于iOS 9)在UIStackView中包装旋转子视图,并使用axis属性重新排列设备旋转时的子视图,或者(对于iOS 8)手动旋转设备旋转时的子视图(请参见this answerthis sample code)。

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

附录:在Technical Q&A QA1688中解释了对shouldAutorotatesupportedInterfaceOrientations的调用没有传播到子视图控制器的原因

从iOS 6开始,只有最上面的视图控制器(与UIApplication对象一起)参与决定是否旋转以响应设备方向的更改。通常,显示内容的视图控制器是UINavigationControllerUITabBarController或自定义容器视图控制器的子级。您可能会发现自己需要对容器视图控制器进行子类化,以便修改其supportedInterfaceOrientationsshouldAutorotate方法返回的值。

在Swift中,您可以使用override those methods by using extensions

票数 14
EN

Stack Overflow用户

发布于 2016-08-10 21:38:42

来自iOS developer库Technical Q&A

当系统确定界面必须旋转时,通过对应用程序的窗口应用旋转转换来实现

自动旋转。然后,该窗口针对新的方向调整其边界,并通过调用每个视图控制器和表示控制器的-viewWillTransitionToSize:withTransitionCoordinator:方法,在视图控制器层次结构中向下传播此更改。向此方法的调用提供一个转换协调器对象,该对象包含窗口的当前转换和新转换的增量,可以通过向转换协调器发送-targetTransform消息来检索该对象。您的视图控制器或表示控制器可以派生出适当的逆变换,并将其应用于目标视图。这将使窗口变换在该特定视图上的效果无效,并在界面的其余部分正常旋转时显示视图在其当前方向上保持不变。

例如,如果您有一个名为noRotatingView的视图

代码语言:javascript
复制
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上做一个演示项目

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38684986

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档