私がやろうとしていること:
親ビューコントローラーによって管理されている親ビューSHOULD NOT ROTATE。
子ビューコントローラーによって管理される子ビューすべての方向に回転(SHOULD ROTATEする必要があります。
私が試したこと:
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 Deployment Infoでサポートされている方向は、4つすべてに設定されています。
得られるもの:
ビューは回転しません。親の回転をすべてに設定すると、すべてのビューが一緒に回転します。つまり、全部かゼロかです。
更新
UIDeviceOrientationDidChangeNotificationのオブザーバーを配置して、UIDevice.currentDevice()。orientationを使用して回転するときchildView CGAffaineTransformMakeRotateを使用すると、望ましい結果が得られます。ただし、横向きに回転し、通知センターを引き下げようとした場合(またはシステム通知を取得した場合)は、引き続き縦向き(アプリは元々縦向きのままであるため)、回転childViewは回転して縦向きに戻り、ステータスバー/通知/通知センターを尊重します。
ストックiOSカメラアプリは、私が提示できる最良の例です。メインキャンバスは異なる方向に回転しませんが、ステータスバーはシーンの背後で、デバイスの回転に合わせて回転します。また、サブビューはそれら自体の中で回転し、さまざまな方向を尊重します。私はこの行動を達成しようとしています...
Appleそれら自体、およびそれらが同じリンクを指している Technical Q&A QA189 を使用して多くの前後に行った後、私は以下の流れの方法でこれを行わなければなりませんでした:
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")
}
}
これは、メインビューを静的に保ちながら子ビューを回転させるようです。また、通知が届くと、アプリは適切な方向を知っているようです(マザービューは実際には舞台裏で回転するため)。
jameskとWarif Akhand Rishiに感謝します!
カメラアプリで得られる効果は、次の組み合わせを使用した場合と同様です。
テクニカルノートでは、自動回転の基本的な実装には、アプリケーションのウィンドウに直接変換を適用する必要があると説明されています。
自動回転は、インターフェイスを回転する必要があるとシステムが判断したときに、アプリケーションのウィンドウに回転変換を適用することによって実装されます。次に、ウィンドウは新しい方向に合わせて境界を調整し、この変更を各ビューコントローラーおよびプレゼンテーションコントローラーの
viewWillTransitionToSize:withTransitionCoordinator:
メソッドの呼び出しを介してビューコントローラー階層全体に伝達します。
カメラアプリは自動回転をオプトアウトしないことに注意してください。カメラアプリを使用する場合、通知センターとコントロールセンターの向きはデバイスの向きを反映します。自動回転をオプトアウトしているように見えるのは、カメラアプリ内の特定のビューのみです。実際、 この答え は、このようなアプリが AVCaptureVideoPreviewLayer や-などのAVFoundationクラスによって提供されるvideoGravity
およびvideoOrientation
プロパティを通常使用することを示唆しています AVCaptureConnection 。
使用するアプローチは、親ビューの回転のみを停止するか、UINavigationControllerなどのコンテナービューコントローラーの回転を停止するか(デバイスの向きをロックするなど)によって異なります。
前者の場合、テクニカルノートで説明されている手法を使用して親ビューの方向を修正し、(iOS 9の場合)UIStackViewで回転サブビューをラップし、axis
プロパティを使用してデバイスの回転時にサブビューを再配置します。 、または(iOS 8の場合)デバイスのローテーションでサブビューを手動でローテーションします( this answer および this sample code を参照してください)。
後者の場合、あなたが取っているアプローチは正しい軌道に乗っています。サンプルコードについては、 この答え を参照してください。通知センターに関する問題を診断するには、コードとビューコントローラ階層に関する詳細情報を共有する必要があります。
補遺:shouldAutorotate
およびsupportedInterfaceOrientations
への呼び出しが子View Controllerに伝達されなかった理由は、- テクニカルQ&A QA1688 :
IOS 6以降、最上位のビューコントローラー(
UIApplication
オブジェクトと共に)のみが、デバイスの向きの変化に応じて回転するかどうかを決定します。多くの場合、コンテンツを表示するビューコントローラーは、UINavigationController
、UITabBarController
の子、またはカスタムコンテナーのビューコントローラーです。supportedInterfaceOrientations
およびshouldAutorotate
メソッドによって返される値を変更するために、コンテナービューコントローラーをサブクラス化する必要がある場合があります。
Swiftでは、 拡張機能を使用してこれらのメソッドをオーバーライド できます。
IOS開発者ライブラリから テクニカル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 でデモプロジェクトを作成しようとしました