2025. 2. 3. 16:06ㆍUIKit, SwiftUI, H.I.G
기기 방향 (Orientation)에 대한 이해
이번 글에서는 애플 기기의 방향 - 세로모드 (portrait) / 가로모드(landscape)에 따른 대응을 고민했던 내용을 소개하고자 합니다.
우선, iOS 개발에서 방향은 Orientation이라는 이름으로 정의되어 있습니다.
이 방향 (Orientation)은 다시, 애플리케이션 사용자 기기의 물리적 방향을 뜻하는 Device Orientation과 / 앱의 UI가 화면에 표시되는 방향을 뜻하는 Interface Orientation. 두 가지로 구분할 수 있습니다.
Orientation을 대응하는 것은 별것 아닌 것 같아 보여도, 생각보다 애플리케이션을 개발하는 데 있어 중요한 영향을 미치는데요.
예를 들어 가로 모드 (landscape)에 최적화되어 있는 가로로 긴 레이아웃이 구현되어 있다고 가정해 봅시다.
별도의 기기 방향에 대한 제약이 없거나 / 화면 최적화를 위한 방향 전환을 알리는 Alert 등이 사용자에게 표출되지 않는다면,
사용자는 해당 애플리케이션의 레이아웃을 세로 모드 (portrait)로 사용할 때, 사용할 수 없을 정도의 UI가 보여지게 되겠죠...?
💡 즉, 우리 개발자들은 의도한 UI가 사용자에게 올바르게 보여지게 하기 위해 "기기 방향에 대한 대응"을 수행해야 한다는 의미입니다!
iOS 애플리케이션의 방향을 대응하는 방법은 앞선 위에서 설명했던 두 가지의 방향인
기기의 방향 Device Orientation과 UI의 방향 Interface Orientation을 각각 사용하는 방법으로 구현할 수 있습니다.
1️⃣ 기기의 방향 (Device Orientation)에 맞춰 애플리케이션 대응하기
: 사용자가 보고 있는 현재 기기의 방향을 가져오고 - 그에 따른 화면 레이아웃을 각각 설정해 주는 방법입니다.
혹은, <특정 방향에 대해서는 사용자에게 화면 전환을 유도>하는 별도의 알림 뷰를 표출해주는 방법도 생각할 수 있겠군요!
2️⃣ UI의 방향 (Interface Orientation)을 제한하기
: 별도의 뷰를 만드는 것이 번거로운 일이라면, 애초에 <특정 방향에 대한 뷰만을 제공>하겠다고 제한하는 방법입니다.
두 방법 중 무엇이 더 낫다고 말할 수는 없지만,
전자처럼 기기의 방향에 맞춰 동적으로 모든 레이아웃을 대응할 수 있도록 만드는 것은 간단한 일은 아닐 거라 생각해요!
결국은 애플리케이션 사용자에게 주고 싶은 경험이 무엇이냐에 따라 차이가 날 것 같군요.
만약, 게임이나 동영상 앱처럼 넓은 화면이 필요한 경우에는 가로 모드만 지원하는 것이 적합할 것이구요.
혹은 아이패드 앱에서 텍스트를 읽는 것이 주목적이 되는 앱이라면 가독성이 강조되는 세로 모드만 지원하는 것이 적합하겠죠?
즉, 위와 같은 사례에서는 애플리케이션 사용 중에 방향을 전환하도록 허용하는 것이 <오히려 사용자에게 혼란을 줄 수 있는 경우>에는 후자의 방식대로 Interface Orientation을 제한하는 것이 더 좋다고 볼 수 있습니다.
이 글에서는 두 가지 대응 방식을 모두 소개해보도록 할게요!
방법 1. 기기 방향 (Device Orientation)에 따른 화면 대응하기
현재 사용자의 기기 방향 (Device Orientation)을 기준으로 화면을 대응하기 위해서는,
우선 "현재 사용자의 기기 방향이 무엇인지"를 알 수 있어야 합니다!
사용자의 현재 방향을 받아오기 위해서는 UIDevice.current.orientation 코드를 사용해 UIDeviceOrientation 값을 받아오게 됩니다.
@State private var deviceOrientation = UIDevice.current.orientation
UIDeviceOrientation은 현재 기기의 물리적 방향을 나타내는 열거형 (Enum) 값으로 아래와 같은 case들이 있습니다.
- unknown : 해당 장치의 방향을 알 수 없을 때
- portrait : 일반적인 세로 모드 방향
- portraitUpsideDown : 위아래가 뒤집혀진 형태의 세로 모드 방향 (전면 카메라가 아래쪽에 위치하고 있는 모습)
- landscapeLeft : 가로 모드 왼쪽 방향 (전면 카메라가 왼쪽에 위치하고 있는 모습)
- landscapeRight : 가로 모드 오른쪽 방향 (전면 카메라가 오른쪽에 위치하고 있는 모습)
- faceUp : 기기가 지면과 평행하게 위치했을 때 기기의 화면이 위로 향하고 있는 방향
- faceDown : 기기가 지면과 평행하게 위치했을 때 기기의 화면이 지면을 향하고 있는 방향
즉. 매우 간단하게 현재 기기의 가로 모드와 세로 모드,
그리고 평행한 상태까지 추적해서 각 화면에 대한 분기처리만 해주면 간단하게 기기 방향 상태에 따른 화면 대응이 가능하게 되는 거죠!
if deviceOrientation.isPortrait {
// 세로 화면일 때 보여줄 화면 코드 구현
} else if deviceOrientation.isLandscape {
// 가로 화면일 때 보여줄 화면 코드 구현
} else if deviceOrientation.isFlat {
// 바닥과 평행한 상태일 때 보여줄 화면 코드 구현
}
하지만, 위 코드로는 초기 화면 상태만 가져올 수 있습니다.
지속적으로 기기의 방향이 바뀌는 것을 실시간으로 추적하기 위해서는 NotificationCenter를 사용해 기기 방향을 받아올 필요가 있죠.
뷰의 시작과 끝 부분에 알림 (NotificationCenter)을 구독하고 해지할 수 있는 코드를 추가해 주겠습니다. (UIKit 기준, init과 deinit에 해당)
각각 구독의 시작과 끝을 beginGeneratingDeviceOrientationNotifications() 메서드와 endGeneratingDeviceOrientationNotifications() 메서드를 사용해서 지정할 수 있습니다.
*해당 메서드는 iOS 기기의 가속도계 (accelerometer) 센서를 사용하여 방향 값을 받아오며, 센서의 활성화에 따라 배터리 소모가 달라질 수 있습니다.
.onAppear {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
}
.onDisappear {
UIDevice.current.endGeneratingDeviceOrientationNotifications()
}
이후, SwiftUI 코드 기준에서는 onReceive 클로저 부분에서
UIDevice.orientationDidChangeNotification 코드를 통해 기기의 방향 변화 값을 추적하여 업데이트해주면 되겠죠?
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
deviceOrientation = UIDevice.current.orientation
}
방법 2. UI 방향 (Interface Orientation) 고정하기
기기 방향에 따른 대응을 해주지 않고, 애초에 사용자에게 보여지는 UI 방향 (Interface Orientation)을 고정하는 방법도 있습니다!
💡 해당 방법이 위의 방법보다 더 자주 사용되는 방식이죠.
Xcode 프로젝트에서는 [App Targets] - [Info] - [Supported interface orientations] 부분에서 지정할 수 있습니다.
아래 이미지에서는 Portrait, Landscape left, Landscape right에 대한 화면을 지원하고 있군요.
UIInterfaceOrientation 열거형 (Enum)의 case 항목들은 아래와 같습니다.
현재 애플 대부분의 기기에서는 홈 버튼이 사라졌지만, 과거 기기의 홈 버튼이 존재하는 위치를 기준으로 좌우를 구분하고 있으니 참고하세유!
- unknown : 해당 장치의 방향을 알 수 없을 때
- portrait : 일반적인 세로 모드에 해당
- portraitUpsideDown : 위아래가 뒤집혀진 형태의 세로 모드에 해당 (홈 버튼 위치 부분이 위로 가있을 때)
- landscapeLeft : 가로 모드 왼쪽 (홈 버튼이 왼쪽에 위치하고 있는 모습)
- landscapeRight : 가로 모드 오른쪽 (홈 버튼이 오른쪽에 위치하고 있는 모습)
💡 헷갈릴 수 있는 landscapeLeft와 landscapeRight 방향 정리하기
- UIDeviceOrientation.landscapeLeft는 UIInterfaceOrientation.landscapeRight와 매핑됩니다.
- UIDeviceOrientation.landscapeRight는 UIInterfaceOrientation.landscapeLeft와 매핑됩니다.
-> 기기의 물리적 방향을 회전할 때, 화면에 표시되는 콘텐츠의 방향은 반대로 회전해야 사용자에게 올바르게 보일 수 있습니다.
예를 들어, 기기를 오른쪽으로 돌리면 - 콘텐츠는 반대로 회전되어야 올바른 방향이기 때문이죠!
Info를 접근할 수 없는 경우에는, (ex. Tuist의 Package나 Swift Playground 같은 경우)
아래와 같이 supportedInterfaceOrientations 값에서 UI 방향 (Interface Orientation)을 지정할 수 있습니다.
만약, 세로모드에 대한 지원 없이 가로모드만 지원하고 싶은 경우,
".landscapeRight와 .landscapeLeft"에 대한 case만 남기면, 사용자가 기기를 세로 모드로 돌리더라도 가로 모드로만 고정되어서 보여질거에요!
Reference
'UIKit, SwiftUI, H.I.G' 카테고리의 다른 글
[UIPasteboard] 클립보드 복사, 붙여넣기 허용 알림 로직 구현하기 (0) | 2025.01.22 |
---|---|
[UIAlertController] 강제 업데이트 및 사용성 개선 업데이트 Alert 표출하기 (0) | 2025.01.22 |
[UIActivityViewController] 우리 앱에 "공유하기" 기능 (Share Sheet) 구현하는 방법 (1) | 2024.12.23 |
[UIKit] UISheetPresentationController를 사용해서 바텀시트(Sheets)를 만들어보자 (1) | 2024.08.30 |
[iOS] 키보드 레이아웃을 가져오는 개선된 방법 (NotificationCenter to Keyboard Layout Guide) (3) | 2024.08.28 |