내 앱이 모든 방향을 지원했기 때문에. 특정 UIViewController에 세로 모드 만 잠그고 싶습니다.
예를 들어 탭이있는 응용 프로그램이고 로그인보기가 모달로 나타날 때 사용자가 장치를 회전하는 방법이나 현재 장치 방향에 관계없이 로그인보기 만 세로 모드로 설정하고 싶습니다.
답변:
여러 탐색 컨트롤러 및 / 또는 탭보기 컨트롤러가있는 것과 같이 복잡한보기 계층 구조가있는 경우 상황이 매우 지저분해질 수 있습니다.
이 구현은 개별 뷰 컨트롤러에 배치하여 방향을 잠그고 싶을 때 설정합니다. 앱 델리게이트에 의존하여 하위 뷰를 반복하여 찾는 대신.
스위프트 3, 4, 5
AppDelegate에서 :
/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
다른 전역 구조체 또는 도우미 클래스에서 여기에 AppUtility를 만들었습니다.
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
/// OPTIONAL Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}
}
그런 다음 원하는 ViewController에서 방향을 잠그고 싶습니다.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppUtility.lockOrientation(.portrait)
// Or to rotate and lock
// AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Don't forget to reset when view is being removed
AppUtility.lockOrientation(.all)
}
iPad 또는 Universal App
대상 설정-> 일반-> 배포 정보에서 "전체 화면 필요"가 선택되어 있는지 확인합니다. supportedInterfaceOrientationsFor
확인하지 않으면 delegate가 호출되지 않습니다.
Requires full screen
Slide Over 및 Split View에서 앱을 사용할 수 없습니다. Apple의 iPad에서 멀티 태스킹 향상 채택을 참조하십시오 . 나는이 대답이 가능하게 필요로하지 않는다Requires full screen
스위프트 4
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
ViewController는 세로 방향 만 필요한 경우 다음 줄을 추가하십시오. ViewController가 세로 모드를 표시하기 위해 필요한 모든 것에 이것을 적용해야합니다.
override func viewWillAppear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}
그러면 장치의 물리적 방향에 따라 다른 Viewcontroller의 화면 방향이됩니다.
override func viewWillDisappear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.all)
}
func application
이 기능을 응용 프로그램 위임 내를func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock ?
스위프트 3 & 4
다음 supportedInterfaceOrientations
과 같이 특정 UIViewController 의 속성을 설정합니다 .
class MyViewController: UIViewController {
var orientations = UIInterfaceOrientationMask.portrait //or what orientation you want
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
get { return self.orientations }
set { self.orientations = newValue }
}
override func viewDidLoad() {
super.viewDidLoad()
}
//...
}
최신 정보
당신이 때이 솔루션은 작동 viewController
되고 있지 임베디드 UINavigationController
, 부모의 ViewController에서 방향 상속 때문이다.
이 경우 하위 클래스를 만들고 UINavigationViewController
여기에 이러한 속성을 설정할 수 있습니다.
초상화를 강제로 잠 그려면 다음 코드를 추가하십시오.
override func viewDidLoad() {
super.viewDidLoad()
// Force the device in portrait mode when the view controller gets loaded
UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation")
}
override func shouldAutorotate() -> Bool {
// Lock autorotate
return false
}
override func supportedInterfaceOrientations() -> Int {
// Only allow Portrait
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
// Only allow Portrait
return UIInterfaceOrientation.Portrait
}
AppDelegate에서-supportedInterfaceOrientationsForWindow를 전체 애플리케이션이 지원할 방향으로 설정합니다.
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.All
}
이것은 귀하의 문제 및 기타 관련 문제에 대한 일반적인 솔루션입니다.
1. 보조 클래스 UIHelper를 만들고 다음 메서드를 추가합니다.
/**This method returns top view controller in application */
class func topViewController() -> UIViewController?
{
let helper = UIHelper()
return helper.topViewControllerWithRootViewController(rootViewController: UIApplication.shared.keyWindow?.rootViewController)
}
/**This is a recursive method to select the top View Controller in a app, either with TabBarController or not */
private func topViewControllerWithRootViewController(rootViewController:UIViewController?) -> UIViewController?
{
if(rootViewController != nil)
{
// UITabBarController
if let tabBarController = rootViewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController {
return self.topViewControllerWithRootViewController(rootViewController: selectedViewController)
}
// UINavigationController
if let navigationController = rootViewController as? UINavigationController ,let visibleViewController = navigationController.visibleViewController {
return self.topViewControllerWithRootViewController(rootViewController: visibleViewController)
}
if ((rootViewController!.presentedViewController) != nil) {
let presentedViewController = rootViewController!.presentedViewController;
return self.topViewControllerWithRootViewController(rootViewController: presentedViewController!);
}else
{
return rootViewController
}
}
return nil
}
2. 당신의 욕망 행동으로 프로토콜을 만듭니다. 당신의 특정한 경우는 초상화가 될 것입니다.
프로토콜 orientationIsOnlyPortrait {}
참고 : 원하는 경우 UIHelper 클래스 상단에 추가하세요.
3. 뷰 컨트롤러 확장
귀하의 경우 :
class Any_ViewController: UIViewController,orientationIsOnlyPortrait {
....
}
4. 앱 델리게이트 클래스에서 다음 메서드를 추가합니다.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
let presentedViewController = UIHelper.topViewController()
if presentedViewController is orientationIsOnlyPortrait {
return .portrait
}
return .all
}
최종 노트 :
새 버전의 Swift를 사용하려면 이것을 시도하십시오.
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.portrait
}
이 스레드에는 많은 훌륭한 답변이 있지만 내 요구와 일치하는 것은 없습니다. 각 탭에 탐색 컨트롤러가있는 탭 앱이 있고 하나의보기는 회전해야하고 다른보기는 세로로 잠 가야했습니다. 내비게이션 컨트롤러가 어떤 이유로 하위 뷰의 크기를 제대로 조정하지 않았습니다. 이 답변 과 결합하여 (Swift 3에서) 해결책을 찾았고 레이아웃 문제가 사라졌습니다. @bmjohns가 제안한대로 구조체를 만듭니다.
import UIKit
struct OrientationLock {
static func lock(to orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lock(to orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
self.lock(to: orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
그런 다음 UITabBarController 하위 클래스 :
import UIKit
class TabBarController: UITabBarController, UITabBarControllerDelegate {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.delegate = self
}
func tabBarControllerSupportedInterfaceOrientations(_ tabBarController: UITabBarController) -> UIInterfaceOrientationMask {
if tabBarController.selectedViewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
return .allButUpsideDown
} else if let navController = tabBarController.selectedViewController as? UINavigationController, navController.topViewController is MyViewControllerInANavControllerThatShouldRotate {
return .allButUpsideDown
} else {
//Lock view that should not be able to rotate
return .portrait
}
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
OrientationLock.lock(to: .allButUpsideDown)
} else if let navController = viewController as? UINavigationController, navController.topViewController is MyViewControllerInANavigationControllerThatShouldRotate {
OrientationLock.lock(to: .allButUpsideDown)
} else {
//Lock orientation and rotate to desired orientation
OrientationLock.lock(to: .portrait, andRotateTo: .portrait)
}
return true
}
}
스토리 보드의 TabBarController 클래스를 새로 만든 하위 클래스로 변경하는 것을 잊지 마십시오.
다음은 Swift 4.2 (iOS 12.2)에서 저를 위해 작동하는 간단한 방법입니다 UIViewController
. shouldAutorotate를 비활성화하려는 경우에 이것을 넣으십시오 .
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
.portrait
부분은 어떤 방향으로 (들)을 유지하기에, 당신 등이 변경할 수를 알려줍니다. 선택은 : .portrait
, .all
, .allButUpsideDown
, .landscape
, .landscapeLeft
, .landscapeRight
, .portraitUpsideDown
.
가로 방향을 앱의 모든보기로 설정하고 하나의보기 만 모든 방향으로 허용하려면 (예 : 카메라 롤을 추가 할 수 있음) :
AppDelegate.swift에서 :
var adaptOrientation = false
에서 : didFinishLaunchingWithOptions
NSNotificationCenter.defaultCenter().addObserver(self, selector: "adaptOrientationAction:", name:"adaptOrientationAction", object: nil)
AppDelegate.swift의 다른 위치 :
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
return checkOrientation(self.window?.rootViewController)
}
func checkOrientation(viewController:UIViewController?)-> Int{
if (adaptOrientation == false){
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}else {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
}
func adaptOrientationAction(notification: NSNotification){
if adaptOrientation == false {
adaptOrientation = true
}else {
adaptOrientation = false
}
}
그런 다음 모든 방향을 가질 수 있도록 원하는 뷰로 이동합니다.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "YOURSEGUE") {
NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
}
}
override func viewWillAppear(animated: Bool) {
if adaptOrientation == true {
NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
}
}
마지막으로 장치 방향을 선택하십시오.-세로-가로 왼쪽-가로 오른쪽
다음으로 새 확장 만들기
import UIKit
extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
extension UITabBarController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
bmjohns-> 당신은 나의 구세주입니다. 이것이 유일한 작업 솔루션입니다 (AppUtility 구조체 사용).
이 클래스를 만들었습니다.
class Helper{
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
/// OPTIONAL Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
}
지시 사항을 따르면 모든 것이 Swift 3-> xcode 버전 8.2.1에서 완벽하게 작동합니다.
iOS 10 및 11부터 iPad는 Slide Over 및 Split View를 지원합니다. Slide Over 및 Split View에서 앱을 활성화하려면 체크를 해제 Requires full screen
해야 합니다. 즉 , 앱이 Slide Over 및 Split View를 지원하려는 경우 허용 된 답변을 사용할 수 없습니다 . Apple의 Adopting Multitasking Enhancements on iPad 에서 자세히 알아보십시오 .
나는 (1) 선택 취소 Requires full screen
, (2) 하나의 함수 만 구현할 수있는 솔루션이 있습니다 ( appDelegate
특히 대상 뷰 컨트롤러를 수정하고 싶지 않거나 수정할 수없는 경우), (3) 재귀 호출을 피할 수 있습니다. 도우미 클래스 나 확장이 필요하지 않습니다.
appDelegate.swift (Swift 4)
func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
// Search for the visible view controller
var vc = window?.rootViewController
// Dig through tab bar and navigation, regardless their order
while (vc is UITabBarController) || (vc is UINavigationController) {
if let c = vc as? UINavigationController {
vc = c.topViewController
} else if let c = vc as? UITabBarController {
vc = c.selectedViewController
}
}
// Look for model view controller
while (vc?.presentedViewController) != nil {
vc = vc!.presentedViewController
}
print("vc = " + (vc != nil ? String(describing: type(of: vc!)) : "nil"))
// Final check if it's our target class. Also make sure it isn't exiting.
// Otherwise, system will mistakenly rotate the presentingViewController.
if (vc is TargetViewController) && !(vc!.isBeingDismissed) {
return [.portrait]
}
return [.all]
}
편집하다
@bmjohns는이 함수가 iPad에서 호출되지 않는다고 지적했습니다. 나는 확인했고 그렇습니다. 그래서 좀 더 테스트를했고 몇 가지 사실을 알아 냈습니다.
Requires full screen
iPad에서 Slide Over 및 Slide View를 활성화하고 싶기 때문에 선택 취소했습니다 . 이를 위해서는 앱이 Info.plist :에서 iPad의 4 가지 방향을 모두 지원해야합니다 Supported interface orientations (iPad)
.내 앱은 Facebook과 동일한 방식으로 작동합니다. iPhone에서는 대부분 세로 모드로 고정되어 있습니다. 전체 화면으로 이미지를 볼 때 사용자가 더 나은보기를 위해 가로로 회전 할 수 있습니다. iPad에서 사용자는 모든 뷰 컨트롤러에서 모든 방향으로 회전 할 수 있습니다. 따라서 iPad가 Smart Cover에 섰을 때 앱이 멋지게 보입니다 (왼쪽 가로).
iPad에서를 호출하려면 application(_:supportedInterfaceOrientationsFor)
Info.plist에서 iPad의 경우 세로 만 유지합니다. 앱이 Slide Over + Split View 기능을 잃게됩니다. 그러나 한 곳에서 모든 뷰 컨트롤러의 방향을 잠 그거나 잠금 해제 할 수 있으며 ViewController 클래스를 수정할 필요가 없습니다.
마지막으로이 함수는 뷰가 표시 / 제거 될 때 뷰 컨트롤러의 수명주기에서 호출됩니다. 앱이 다른 시간에 잠금 / 잠금 해제 / 방향 변경이 필요한 경우 작동하지 않을 수 있습니다.
이에 대한 실제 테스트 솔루션 . 내 예제에서는 전체 앱이 세로 모드 여야하지만 한 화면의 방향 만 가로 모드 여야합니다.
위 답변에 설명 된대로 AppDelegate의 코드.
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
return self.orientationLock
}
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
그런 다음 가로 방향 뷰 컨트롤러가 표시 / 푸시되기 전에이 코드를 작성하십시오.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}
그런 다음 실제 viewcontroller에이 코드를 작성하십시오 (가로보기 용).
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape)
}
위의 @bmjohn의 답변 덕분입니다. 다음은 작동하는 Xamarin / C #입니다. 다른 사람의 필사 시간을 절약하기 위해 해당 답변 코드 버전입니다.
AppDelegate.cs
public UIInterfaceOrientationMask OrientationLock = UIInterfaceOrientationMask.All;
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
{
return this.OrientationLock;
}
Static OrientationUtility.cs 클래스 :
public static class OrientationUtility
{
public static void LockOrientation(UIInterfaceOrientationMask orientation)
{
var appdelegate = (AppDelegate) UIApplication.SharedApplication.Delegate;
if(appdelegate != null)
{
appdelegate.OrientationLock = orientation;
}
}
public static void LockOrientation(UIInterfaceOrientationMask orientation, UIInterfaceOrientation RotateToOrientation)
{
LockOrientation(orientation);
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)RotateToOrientation), new NSString("orientation"));
}
}
컨트롤러보기 :
public override void ViewDidAppear(bool animated)
{
base.ViewWillAppear(animated);
OrientationUtility.LockOrientation(UIInterfaceOrientationMask.Portrait, UIInterfaceOrientation.Portrait);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
OrientationUtility.LockOrientation(UIInterfaceOrientationMask.All);
}
나는 약간의 실험을했고이 문제에 대한 깨끗한 해결책을 찾았습니다. 접근 방식은 view-> tag를 통한 뷰 태그 지정을 기반으로합니다.
대상 ViewController에서 다음 코드 예제와 같이 루트 뷰에 태그를 할당하십시오.
class MyViewController: BaseViewController {
// declare unique view tag identifier
static let ViewTag = 2105981;
override func viewDidLoad()
{
super.viewDidLoad();
// assign the value to the current root view
self.view.tag = MyViewController.ViewTag;
}
마지막으로 AppDelegate.swift에서 현재 표시된 뷰가 태그가 지정된 뷰인지 확인합니다.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
if (window?.viewWithTag(DesignerController.ViewTag)) != nil {
return .portrait;
}
return .all;
}
이 접근 방식은 내 시뮬레이터로 테스트되었으며 제대로 작동하는 것 같습니다.
참고 : 현재 MVC가 탐색 스택의 일부 하위 ViewController와 겹치는 경우 표시된보기도 찾을 수 있습니다.
가로 및 세로 잠금 및 방향 변경을위한 최상의 솔루션 :
YouTube에서이 비디오를보십시오 :
https://m.youtube.com/watch?v=4vRrHdBowyo
이 튜토리얼은 가장 좋고 간단합니다.
또는 아래 코드를 사용하십시오.
// 1- 두 번째 viewcontroller에서 landscapeleft를 설정하고 첫 번째 viewcontroller에서 portrat를 설정합니다.
// 2- NavigationController를 사용하는 경우 확장을 추가해야합니다.
import UIKit
class SecondViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
}
override open var shouldAutorotate: Bool {
return false
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
override func viewDidLoad() {
super.viewDidLoad()
}
//write The rest of your code in here
}
//if you use NavigationController, you should add this extension
extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
}
}