[UiKit] 가로모드 세로모드 감지하기

·2024년 12월 17일
0

iOS-posting

목록 보기
2/3

Udemy강의듣던 중 이런 실로폰 관련 프로젝트로 소리내보는 실습을 했는데, 그 이후 개인적으로 여기서 화면을 눕혔을 때 실로폰이 오른쪽(가로모드)처럼 동일하게 Vertical stackview로 나오는거를 좀 Horizontal로 바꿔주고 싶어서 어떻게 유저가 가로모드를 켰을 때를 감지하지? 싶어서 좀 찾아보게 되었다.


화면을 가로로 눕혔을 때 처리를 해주려면 ?

how to detect(감지?) orientation 이라고 검색해서 다음 자료를 찾을 수 있었다.

StackOverflow-가로모드 감지 관련 글

채택받은 코드를 살펴보면..

UIDevice.current.orientation.isLandscape

를 사용하면 되는 듯하다. UIDevice에서 현재 orientation이 Landscape(가로모드)인지? 해서 Bool값으로 return해주는 것 같은데, 더 자세히 살펴보면, 바로 확인할 수가 있다.

UIDevice-공식문서

orientation property 활용해서 가로,세로모드를 알 수 있고, 혹은 orientationDidChangeNotification을 활용해서 알림을 받을 수도 있다고 작성되어 있다.

UIDeviceOrientation 공식문서

아까 예제코드에서 봤던 메소드들을 여기서 확인할 수 있다. 바로 작성을 해보면

1 - isLandScape써보기

    @IBAction func pressC(_ sender: UIButton) {
        playSound("C")
        print(UIDevice.current.orientation.isLandscape)
        updateStackViewOrientation()
    }
    
    func updateStackViewOrientation() {
        if UIDevice.current.orientation.isLandscape {
            xylophoneView.axis = .horizontal
        } else {
            xylophoneView.axis = .vertical
        }
    }

UIDevice.current.orientation.isLandscape가 true면 stackView를 horizontal으로, 그게 아닌 경우엔 다시 vertical으로 변경해주는 함수를 작성해서 적용해주었다.

적용한 영상 !

Landscape일 때, C버튼을 눌렀을 때 landscape임을 감지하고, stackView의 축을 horizontal로 변경한 영상이다

2 - orientationDidChangeNotification

StackoverFlow 자료

NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)

이런식으로 사용하라고 써있는데, NotificationCenter문서를 보면

Objects register with a notification center to receive notifications (NSNotification objects) using the addObserver(:selector:name:object:) or addObserver(forName:object:queue:using:) methods. When an object adds itself as an observer, it specifies which notifications it should receive. An object may therefore call this method several times in order to register itself as an observer for several different notifications._

오브젝트를 알림센터에 등록하고, addObserver 메소드를 활용해서 수신을 받을 수 있다고 한다.
그래서 예제코드에 나온대로 addObserver 메소드를 호출해서 selector에 수신을 받고 어떻게 해줄지를 넣어주면 되고, name으로는 아까 찾았던 UIDevice.orientationDidChangeNotification를 사용하면 되는 것인듯 보인다!

바로 적용을 해보면!

적용 영상(자동 StackView 축 변경)

코드


import AVFoundation
import UIKit

class ViewController: UIViewController {
    var player: AVAudioPlayer!

    @IBOutlet var xylophoneView: UIStackView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 앱을 켰을 때 StackView 방향 설정 ( 가로 모드에서 킬 수도 있기 때문 ! )
        updateStackViewOrientation()

        // NotificationCenter에 적용하기
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleOrientationChange),  
            // 알림이 도착하면 실행할 함수를 넣어주면 됩니다 ! 
            name: UIDevice.orientationDidChangeNotification, //orientationDidChangeNotification 등록
            object: nil
        )
    }

    deinit {
        // NotificationCenter에서 추가해준 Observer 해제
        NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
    }

....
    // 가로/세로에 따라 StackView 방향 업데이트
    @objc func handleOrientationChange() {
        updateStackViewOrientation()
    }

    func updateStackViewOrientation() {
        if UIDevice.current.orientation.isLandscape {
            xylophoneView.axis = .horizontal
        } else if UIDevice.current.orientation.isPortrait {
            xylophoneView.axis = .vertical
        }
    }
}

코드 설명

  1. Notification 등록

    selector에 이제 알림이 도착하면 실행할 메소드가 들어가게되고,
    UIDevice.orientationDidChangeNotification은 이제 방향이 변경되면 이제 selector에 등록한 메소드를 실행해야하는구나!를 감지할 수 있는 더듬이(?)라고 보시면 될 것 같다 ! object는 추가적인 조건을 설정할 때 사용하는데, 현재는 가로 , 세로 모드 감지만 필요하므로 nil로 처리해주면 된다.
  2. handleOrientationChange(){}

    updateStackViewOrientation에서 현재 세로인지 가로인지 판단해서 축을 결정해주니 쓰던거를 이제 그대로 사용해주면 될 것이다. 다만 @objc 가 들어간 이유는 NotificationCenter가 Objective-C기능을 사용해서, selector를 통해서 메소드를 호출하려면 Object-C에서 이를 인식할 수 있어야해서 Objective-C 런타임에 노출 될 수 있게 @objc 선언해줌으로서 objc가 필요한 친구입니다..! 라고 꼬리표를 달아주는 거라고 이해하시면 될 것 같다 !
  3. deinit은 뭔데?

    이게 NotificationCenter에 addObserver를 해줬기 때문에, 이걸 해제해주지 않으면 계속해서 이벤트를 감지하려고 하고 있어서 수동으로 메모리를 해제해줘야하는데, 이때 deinit으로 해주면 된다. 지금은 페이지가 하나라서 괜찮지만 나중에 여러개의 ViewController 있으면 해당 ViewController가 메모리에 해제되었음에도 계속 메모리 누수를 발생시킬 것이다.
  • 물론 iOS9+에서는 클로저 기반으로 코드를 짜면 자동으로 해제될 수 있고, NotificationCenter보다는 viewWillTransition을 사용하면 해제도 필요없이 더 간단하다는 이야기가 있는데 다음에 기회가 되면 사용해봐야 겠다.

추가적으로 시뮬레이터에서 가로모드가 적용이 안될때는 프로젝트 설정해서 Portrait(세로모드)말고도 나머지를 체크해줘야한다.

가로모드 설정

iOS시뮬레이터에서 설정

1. 상단바에서 설정

2. 시뮬레이터에서 설정

profile
기억보단 기록을

0개의 댓글