디바이스 회전 대응

2025. 4. 26. 22:28·iOS/UIKit
반응형

👋 들어가기 전

최근 들어 iPad 앱을 도전해보고 싶은 마음이 점점 커지고 있다.

그래서 앱에서 디바이스를 회전했을 때 대응하는 과정을 한번 학습해보고 싶었다.

🏁 학습할 내용

먼저 가장 필요한 내용이 화면 회전 시 호출될 생명주기와

대응코드가 들어갈 위치를 알아보자.

 

이후 엣지 케이스 대응을 위한 추가학습 미리보기까지 정리해보자. 

  • viewWillTransition
  • layoutSubview

🔄  viewWillTransition

⭐️ 정의

공식문서를 살펴보면 viewWillTransition은 뷰들을 포함하는 컨테이너의 사이즈가
변경되면 호출된다고 써 있다.

 

가장 대표적인 컨테이너 사이즈 변화는 디바이스 회전이 있다.

아이패드 일 때는 스플릿 뷰도 포함된다.

🔥 구성요소

 override func viewWillTransition(
    to size: CGSize,
    with coordinator: any UIViewControllerTransitionCoordinator
  ) {
    
  }

 

1. size

  • 컨테이너의 변화된 새로운 사이즈

2. coordinator

  • 전환에 대한 진행 정보를 제공하고, 변화를 관리하는 객체

⌨️ 실습

✅ 증명

먼저 언제 호출되는 지 살펴보자.

위에서 설명한대로 회전과 스플릿을 진행

 

예상 했던대로 회전과 스플릿 뷰에서 모두 호출된는 것을 검증했다.

🍎 animate vs animateAlongsideTransition

coordinator에서 제공하는 api를 보면 animation과 관련된 2개의 메서드가 있다.

역활과 차이점을 살펴보자.

구분 animate animateAlongsideTransition
스타일 최신 구버전
여갛ㄹ 전환 애니메이션에서 추가로 실행될 애니메이션 적용

🖼️ layoutSubviews()

⭐️ 정의

자신의 자식 뷰들의 배치를 잡을 때 호출된다.

여기서 배치를 잡을 때는 재배치도 포함된다.

 

재배치는 언제 이뤄질까?

 

프레임 크기가 변경되거나 제약조건이 변경되거나 다양한 경우가 존재하지만

결국에는 시스템이 updateCycle 시 갱신이 필요하다는 변화가 느껴져야 호출된다.


⌨️ 실습

한번 지금까지 배운 개념을 잠깐 적용해보자.

 

가로모드와 세로모드일 때 AView의 높이를 변경해보고

layoutSubviews가 호출되는 지 살펴보자.

AView.swift

class AView: UIView {

  private let label: UILabel = {
    let label = UILabel()
    label.text = "123123124141"
    return label
  }()

  override func layoutSubviews() {
    super.layoutSubviews()
    print(#function)
  }

  init() {
    super.init(frame: .zero)
    self.addSubview(label)

    label.translatesAutoresizingMaskIntoConstraints = false
    label.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
    label.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
    label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
    label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

    label.textColor = .blue
  }
  
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

}

ViewController.swift

final class ViewController: UIViewController {
  private let aView = AView()
  private var portraitConstraints: NSLayoutConstraint?
  private var landscapeConstraints: NSLayoutConstraint?

  override func viewWillTransition(
    to size: CGSize,
    with coordinator: any UIViewControllerTransitionCoordinator
  ) {
    let isPortrait = size.width < size.height
    coordinator.animate(alongsideTransition: nil) { [weak self] _ in
      guard let self else { return }

      if isPortrait {
        landscapeConstraints?.isActive = false
        portraitConstraints?.isActive = true
      } else {
        portraitConstraints?.isActive = false
        landscapeConstraints?.isActive = true
      }
    }
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
    view.addSubview(aView)
    aView.translatesAutoresizingMaskIntoConstraints = false

    aView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    aView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

    aView.backgroundColor = .black

    portraitConstraints = aView.heightAnchor.constraint(equalToConstant: 100)
    landscapeConstraints = aView.heightAnchor.constraint(equalToConstant: 200)

    portraitConstraints?.isActive = true

  }
}

결과

예측한 동작이 작동해서 너무 좋다...


❓그러면 여기서 질문

UICollectionView와 UITableView와 같은 cell을 통한 데이터를 표현할 때

cell들의 layoutSubview()를 어떻게 호출하고

 

데이터는 그대로이고 레이아웃의 변화가 일어날 때 어떤 일들이 일어날까??

 

그 내용은 UICollectionView와 UITableView 파트로 나눠서 다음 포스팅에서 진행하겠다..


😀 소감 및 마무리

언젠간 꼭 이 지식들을 이용해 가로모드도 자연스럽게 지원되는 앱을 만들고 싶다.


출처

https://developer.apple.com/documentation/uikit/uicontentcontainer/viewwilltransition(to:with:)

 

viewWillTransition(to:with:) | Apple Developer Documentation

Notifies the container that the size of its view is about to change.

developer.apple.com

https://developer.apple.com/documentation/uikit/uiview/layoutsubviews()

 

layoutSubviews() | Apple Developer Documentation

Lays out subviews.

developer.apple.com

https://hamp.tistory.com/23

 

생명주기 (3) [ View 생명주기 ]

오늘은 iOS 생명주기의 마지막 단계인 View의 생명주기에 대해 알아보자. 전체적인 생명주기는 다음 그림과 같다. init1) init((coder:))스토리보드나 xib파일은 활용하여 화면을 만들 때 컴파일러가

hamp.tistory.com

https://hamp.tistory.com/24

 

생명주기 (4) [ 업데이트 Cycle ]

애니메이션과 트랜지션과 같은 조금 더 개선된 UX를 주기 위해 다양한 코드를 적었는데 원하는 대로 동작하지 않는 경우가 자주 발생하고 나는 그게 View Rendenring을 재대로 이해하지 못하고 있는

hamp.tistory.com

 

반응형

'iOS > UIKit' 카테고리의 다른 글

HitTest와 touchesBegan은 무슨 관계가 있을까?  (0) 2025.05.30
레이아웃 핵심 프로세스  (0) 2025.04.27
Transitioning  (0) 2025.04.19
UIStackView 뿌시기  (0) 2025.01.29
PhotoPicker 최적화하기  (4) 2024.12.29
'iOS/UIKit' 카테고리의 다른 글
  • HitTest와 touchesBegan은 무슨 관계가 있을까?
  • 레이아웃 핵심 프로세스
  • Transitioning
  • UIStackView 뿌시기
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (340)
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (41)
        • swift (34)
        • python (6)
        • Kotlin (1)
      • iOS (135)
        • UIKit (37)
        • Combine (1)
        • SwiftUI (34)
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (2)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (21)
        • 어노테이션 (6)
        • 튜토리얼 (14)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (21)
        • 이론 (10)
        • MCP (1)
        • LangGraph (10)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    dispatch
    SwiftUI
    GIT
    protocol
    프로그래머스
    dfs
    AVFoundation
    IOS
    Tuist
    dp
    lifecycle
    boostcamp
    Swift
    property
    UIKit
    CS
    Spring
    백준
    투포인터
    concurrency
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
디바이스 회전 대응
상단으로

티스토리툴바