[iOS][UIKit] 특정 뷰만 UI orientation 가로모드, 세로모드로 강제하기 (v1.1.1)

Madeline👩🏻‍💻·2024년 5월 22일
1

iOS study

목록 보기
52/61
post-custom-banner


(image 땡스투 위키피디아입니다.)

Forcing UI Orientation

오늘은 UI Orientation을 가로모드로, 세로모드로 강제하는 방법에 대해 알아볼텐데요,
앱 전체를 가로, 세로로 바꾸는건 너무나 쉽지만,
특정 뷰만 가로로, 세로로 바꾸는건 좀 까다로워 보입니다.

그리고 우선 iOS 16부터 방법이 바뀌었습니다.
여러분 버전 대응하십셔!

🍎: orientation 강제 권하지 않는다(지만 어떡해 해야지)

view Will Apear 시점에 선언해야 잘 바뀐답니다.

세로모드 강제

private func forcePortraitOrientation() {
        if #available(iOS 16.0, *) {
            let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
            windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait))
        } else {
            let value = UIInterfaceOrientation.portrait.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
        }
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }

    override var shouldAutorotate: Bool {
        return true
    }

가로모드 강제

private func forceLandscapeOrientation() {
        if #available(iOS 16.0, *) {
            let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
            windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeRight))
        } else {
            let value = UIInterfaceOrientation.landscapeRight.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
        }
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscape
    }

    override var shouldAutorotate: Bool {
        return true
    }

shouldAutorotate 값을 바꾸면 디바이스 가로로 눕히거나 세로로 돌리면, 화면이 고정되거나 풀리거나의 여부를 관리할 수 있겠지?? 라고 생각했는데요,

-> 3일 뒤 아니라는 것을 꺠달아서 글을 더 첨부합니다.

🤦🏻‍♀️

안되더라구요, 강제..
그러니깐 핸드폰을 가로로 눕히면 가로모드로 잘 나옵니다. 근데 이제 세로로 세우면 UI 가 깨지고 세로로 바뀌어버려요.

문제에 대한 원인분석을 엄청나게 해봤는데,

일단 저는 어떤 뷰는 세로로, 어떤 뷰는 가로로 강제해야 하는 상황이었습니다.

핸드폰 화면 가로, 세로 모드(orientation)에 대해 관여할 수 있는게 뭐가 있을까 나열해봤더니,

원인일까?

1) 아이폰 기본 설정(화면 회전 허용 여부)
2) AppDelegate, SceneDelegate에서 앱 전체에 대한 설정
3) info.plist에서 앱 전체에 대한 설정
4) 뷰별로 위에 써놓은 코드로 관리

이 정도가 있는데, 문제는 얘네가 충돌하면 4번이 무시될 확률이 높다.(3일 전에 쓴 윗 글 내용이죠) ㅎ하하. 실제로 무시당했습니다.

게다가 4번도 뷰들이 NavigationController로 연결되어있는 경우, 상위뷰에서 하위뷰에 대한 영향을 끼칠 가능성도 있구요.

그래서 일단은 어떻게 해결했냐면요,

AppDelegate에는 우선은 세로모드로 강제해두고,
AppDelegate에다가 앱 전체에 대한 전역변수를 선언해서,

var shouldSupportLandscapeOrientation = false

가로모드로 강제해야 하는 뷰에서 이 전역변수를 가져다가 앱 전체에 대한 화면 모드를 바꿔버립니다.

// viewController에서
let appDelegate = UIApplication.shared.delegate as! AppDelegate

override func viewWillAppear(_ animated: Bool) {
        appDelegate.shouldSupportLandscapeOrientation = true
    }

그리고 가로->세로로 돌아가야 하는 시점에는, 가로모드의 마지막 뷰에서 viewWillDisappear 시점에 다시 appdelegate의 전역변수를 다시 true로 바꿔주었습니다.

이렇게 하면 되긴 됩니다.ㅎ
임시방편인거같지만 더 좋은 방법 있으면 알려주세요 제발~

그리고 혹시 SwiftUI로도 특정 뷰만 가로모드 강제할 수 있나요? 이 부분도 아신다면 알려주세요 제발~ 🥕🥕🥕🥕🥕

profile
🍎 Apple Developer Academy@POSTECH 2기, 🍀 SeSAC iOS 4기
post-custom-banner

2개의 댓글

comment-user-thumbnail
2024년 5월 28일

SwiftUI로도 Custom AppDelegate, SceneDelegate쓸 수 있어요. 거기서 뽑아내고 onAppear 시점에 appDelegate.shouldSupportLandscapeOrientation = true 하면 될거같아요

1개의 답글