子视图控制器旋转,同时父视图控制器不

问题描述:

我所试图做的:由母公司 - 视图 - 控制器管理应该无法旋转子视图控制器旋转,同时父视图控制器不

父视图。

子视图是由儿童视图控制器管理就会以到所有方向。


enter image description here

enter image description here


我曾尝试:

ParentViewController

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

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

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

在Xcode部署信息支撑取向被设置为四个。

我会得到什么:

视图的旋转没有。如果我将父级的旋转设置为全部,则所有视图一起旋转。所以这是全部或没有。


UPDATE

,当我试图把一个观察员UIDeviceOrientationDidChangeNotification和使用UIDevice.currentDevice()。方向用CGAffaineTransformMakeRotate旋转childView,我得到想要的结果。但是,即,如果我旋转到横向,并尝试拉下通知中心(或者如果我得到系统通知),它仍然处于纵向方向(因为应用程序本身仍然保留在纵向中),旋转childView旋转回肖像状态栏/通知/通知中心。

股票iOS相机应用程序是我可以提供的最好的例子。主画布不旋转到不同的方向,但状态栏在幕后旋转以遵守设备旋转。此外,子视图也会自我旋转以表达不同的倾向。我试图实现此行为....

+1

不知道这是否会起作用,只是把它当作一个想法。我肯定会设置应用程序只支持一个(人像)方向,然后我会尝试检测设备的旋转(而不是屏幕),并通过在屏幕中间手动旋转视图来响应该设置。我猜'viewWillTransition(to:with:)'不起作用,所以你需要找到一个合适的解决方案。 – Andrej

+0

你的意思是使用CGAffineTransform之类的东西进行旋转? – Gizmodo

+1

是的,完全是CGAffineTransform。你有一个有趣的情况。我很乐意帮忙,并且试着写一些代码来解决这个问题,但是恐怕我会很安静,所以我不能在这里弄脏我的手。 – Andrej

做一个示范项目,经过多次来回与苹果他们的自我,并指向同样的链接Technical Q&A QA1890,我不得不用流动的方式做到这一点:

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 
     }) 
    } 

MainViewController

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仙人所有帮助!

+0

这似乎并不适用于我,如http://*.com/questions/42778355/why-am-i-seeing-a-glitch-in-the-counter-rotation-animation中所述想法为什么? –

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

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

自转,通过施加旋转来实现转换为应用程序的窗口时,系统确定界面必须旋转。窗口然后调整其新方向的界限,并通过调用每个视图控制器和呈现控制器的方法在视图控制器层次结构中向下传播此更改。

请注意,相机应用程序不会选择退出自转:使用相机应用程序时,通知中心和控制中心的方向反映设备的方向。这只是在相机应用程序中的特定视图,似乎选择退出自动旋转。实际上,this answer暗示这样的应用通常利用由诸如AVCaptureVideoPreviewLayerAVCaptureConnection的AVFoundation类提供的videoGravityvideoOrientation属性。

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

如果前者使用技术说明中描述的技术修复父视图的方向,并且(对于iOS 9)在UIStackView中旋转子视图并使用axis属性重新排列设备旋转上的子视图,或(对于iOS 8)手动旋转设备旋转上的子视图(关于其参见this answerthis sample code)。

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

附录:为什么要shouldAutorotatesupportedInterfaceOrientations电话都没有被传播到子视图控制器在Technical Q&A QA1688解释原因:

与iOS 6中,只有最上面的视图控制器(开始沿着UIApplication对象)参与决定是否响应于设备的方向改变而旋转。通常情况下,显示您内容的视图控制器是UINavigationController,UITabBarController或子容器视图控制器的子项。您可能会发现自己需要为容器视图控制器创建子类,以修改其supportedInterfaceOrientationsshouldAutorotate方法返回的值。

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

+0

很好的回复!我仍在阅读链接。正如我在下面提到的,我遇到了使用viewWillTransitionToSize的问题:withTransitionCoordinator:因为我希望motherView在childView旋转时不旋转。如果motherView根本不旋转,viewWillTransitionToSize:withTransitionCoordinator:不会在它自己内被调用。 – Gizmodo

+0

这里的技巧:不要从'shouldAutorotate'返回'false'。使用技术说明中显示的技术来阻止motherView旋转 - 这不会干扰'viewWillTransitionToSize:' - 并使用后者(或'viewWillLayoutSubviews')来相应地旋转子视图。 – jamesk

+0

不幸的是仍然努力使其工作.... – Gizmodo

距离Ios显影剂库Technical Q&A

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

也就是说,如果你有一个命名视图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

+0

你的答案很棒!看看你的示例代码,我仍然会遇到主要问题,即使我在查看Apple的技术文档时仍然遇到以下问题:MotherView不旋转,ChildView旋转。如果包含视图根本不旋转,则不会调用viewWillTransitionToSize方法。这是我仍然卡在... – Gizmodo

+0

@gizmodo我认为母亲的观点旋转在iOS相机应用程序。因此通知中心和控制中心旋转。如果你想锁定母视图,你可以看到[RotateButton](https://github.com/rishi420/RotateButton)。 –

+1

您的TestCameraRotation + RotateButton的组合在这一点上是最有意义的。 1.将MainView放入另一个视图中,并使用viewWillTransitionToSize停止旋转。 1.使用设备方向KVO旋转childView。 – Gizmodo