티스토리 뷰

반응형

 

 

 

안녕하세요 민군입니다! ^-^ 저는 최근 부스트코스 에이스 과정에 참여하게 되었는데요.
오늘은 부스트코스 에이스 학습내용 포스팅 미션으로 네비게이션컨트롤러의 기본 화면전환 기능을 코드로 구현해보는 시간을 가졌습니다.

오늘은 네비게이션컨트롤러 기본 화면전환 기능을 코드로 구현해보는 과정을 공유해보겠습니다. ^-^//

 

 

 

네비게이션 인터페이스


출저 부스트코스 (https://www.edwith.org/boostcourse-ios/lecture/16857/)

네비게이션 인터페이스는 주로 계층적 구조의 화면전환을 위해 사용되는 인터페이스입니다. 네비게이션 인터페이스를 사용하면 특정 여러개의 뷰컨트롤러에 대한 통일 된 틀을 만들어 줄 수 있습니다. + 네비게이션을 통해 뷰컨트롤러를 통합적으로 관리하면 화면전환등의 기능도 더욱 편리하게 사용할 수 있다는 장점도 있습니다.

 

 

네비게이션 컨트롤러


출저 부스트코스 (https://www.edwith.org/boostcourse-ios/lecture/16857/)

네비게이션 컨트롤러는 다수의 뷰컨트롤러를 담을 수 있는 컨테이너 뷰 컨트롤러입니다. 네비게이션 스택을 사용하는데 네비게이션을 통한 화면전환은 스택방식으로 이루어 집니다. LIFO(Last In First Out)방식으로 push, pop을 사용합니다.

이제 코드를 통해 간단한 네비게이션 컨트롤러 화면전환 기능을 사용해보겠습니다. 3개의 뷰컨트롤러, FirstViewController, SecondViewController, ThirdViewController를 통해 네비게이션 컨트롤러 기능을 확인해볼 예정입니다.

 

 

 

네비게이션 컨트롤러 화면전환 코드구현


❋ 앱 델리게이트 (AppDelegate)

싱글턴 클래스인 AppDelegate에서는 앱의 생명주기를 관리합니다. 여기서 먼저 기본 네비게이션컨트롤러와 네비게이션컨트롤러에 맨 처음 띄울 뷰컨트롤러를 정의해 주려고 합니다. 

앱은 아이콘을 눌러 실행하게 되면 @UIApplication 노테이션을 감지하여 해당 AppDelegate클래스의 델리게이트 메서드를 통해 앱의 상태를 감지합니다. 앱을 실행되었을때 실행되는 델리게이트 메서드는 willFinishLaunchingWithOptions에 이어 didFinishLaunchingWithOptions 가 호출되는데요. 앱이 실행되었을때 초기 셋팅은 보통 didFinishLaunchingWithOptions에서 이루어집니다. 

 

 

window = UIWindow(frame: UIScreen.main.bounds)


맨 처음 뷰컨트롤러의 이벤트 관리 등 다양한 작업을 수행해주는 UIWindow 객체를 설정해 줍니다. UIWindow객체의 frame크기는 기기화면에 맞추기 위해 UIScreen의 메인 bounds를 따릅니다(UIScreen.main의 액자 틀에 딱 맞춘 느낌?).

UIWindow객체의 bounds는 이 위에 네비게이션 컨트롤러와 뷰 컨트롤러가 올라갈 예정입니다. 

 

let firstViewController = FirstViewController()
let navigationController = UINavigationController(rootViewController: firstViewController)


메인으로 띄워줄 뷰컨트롤러 인스턴스를 만들어줍니다.
FirstViewController는 UIViewController를 커스터마이징 한 뷰컨트롤러로 밑에서 세부적으로 구현할 예정입니다. 

바로 아래에는 네비게이션컨트롤러를 구현했습니다. 네비게이션컨트롤러 또한 다양한 방법으로 인스턴스 생성이 가능한데, 그 중 한가지 방법으로 위와 같이 rootViewController를 인자값으로 받아 생성할 수 있습니다.  바로 위에서 만든 firstViewController가 rootViewController로써 동작하게 되며, 맨 처음 화면에 나타나게 될것입니다.

window 인스턴스의 프로퍼티 메서드 중 하나인 makeKeyAndVisible()은 현재 레벨의 window창을 쉽게 보여줄 수 있는 메서드로 아는데, UIWindow객체가 생성 시 자동으로 창을 보여주는지 해당 메서드는를 사용하지 않아도 window창이 뜨는 것을 알 수 있었습니다. 이와 관련해서 한분께서 피드백 답변을 주셨습니다. 답변내용은 아래와 같습니다.
중간에 makeKeyAndVisible 부분은 저도 찾아보고 실험해보니 스토리보드가 지정되어 있는 상황에서 appDelegate의 window 프로퍼티를 자동으로 키 윈도우로 지정하고 띄우기 때문에 호출할 필요가 없었던 거더라구요. info.plist에서 스토리보드 참조 지우시고 해보시면 makeKeyAndVisible 을 호출해야만 정상적으로 화면이 나타납니다.

https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623056-window
이 문서를 참조하시면 더 도움이 될 것 같습니다:)


라이노님 피드백 감사합니다 ^-^

 

 

❋ 뷰 (View)

뷰컨트롤러에 사용할 뷰를 정의해 보겠습니다.

네비게이션컨트롤러를 통한 화면전환 기능을 확인하기 위해 각 뷰마다 2개의 UIButton을 구현할 예정입니다. 버튼 텍스트 내용은 위와 같이 기능을 표현하는 텍스트로 설정했습니다. 

FirstView 이외에 SecondView, ThirdView에 대해서는 설명을 생략하려합니다. FirstView와 클래스명만 다르지 내용은 거의 비슷한 복붙코드이기 때문입니다 @_@;;

 

 

makeSubView() 메서드 에서는 버튼 두개를 뷰의 서브뷰로 추가하는 작업을 합니다. 

makeConstraint() 메서드에서는 버튼 두개에 대한 제약값을 간단하게 주었습니다. 

 

 

이어서 정의한 메서드(makeSubView(), makeContraint())를 init메서드에 추가해주었습니다. 뷰의 배경색은 흰색으로 설정해주었습니다.

color literal 기능을 통해 위와 같이 색상 설정을 해줄 수 있습니다. CGColor, UIColor 등의 다양한 포맷 상관없이 간편하게 적용할 수 있다는 장점이 있지만, 반면 훑어볼때 육안으로 색상을 확인해야하는 단점이 있습니다.

이제 뷰컨트롤러에서 해당 뷰를 사용해 볼까요? @_@

 

 

❋ 뷰컨트롤러 (ViewController)

 

 let firstView: FirstView = {
        let firstView = FirstView()
        return firstView
    }()


firstView인스턴스를 미리 정의
해줍니다. 앞서 구현한 FirstView클래스의 인스턴스입니다.

 

override func loadView() {
        super.loadView()
        view = firstView
    }


뷰컨트롤러 생애주기 중 시작 부분에 위치한 loadView
입니다. 뷰컨트롤러를 메모리에 올리기 전 뷰를 만드는 메서드인데요. 위에서 미리 정의한 firstView 인스턴스를 해당 뷰컨트롤러의 뷰, self.view로 설정해줍니다.

FirstViewController 이외로 SecondViewController, ThirdViewController는 비슷한 소스코드로 되어있기에 생략합니다. 

firstView.firstButton.addTarget(self, action: #selector(firstButtonPressed(_:)), for: .touchUpInside)
firstView.secondButton.addTarget(self, action: #selector(secondButtonPressed(_:)), for: .touchUpInside)


아까 만든 FirstView에서 버튼 두개를 만들었었죠? 그 버튼을 동작 시키기 위해 addTarget를 사용합니다. 버튼 내부에서 누르고 뗄 때(.touchUpInside) 호출되는 특정 셀렉터 메서드를 사용할 겁니다. 

셀렉터 메서드 명은 firstButtonPressed, secondButtonPressed가 되겠습니다.

현재 Xcode 10.3 버전 기준, 셀렉터 메서드는 @objc를 붙여주어 구현할 수 있습니다.

 

 

❋ 뷰컨트롤러 버튼 이벤트 (Button Events)

FirstViewController의 버튼이벤트는 위와 같습니다. 

 

    // MARK:- FirstView Button Event
    @objc func firstButtonPressed(_: UIButton) {
        print("pushViewController -> secondView")
        let secondViewController = SecondViewController()
        navigationController?.pushViewController(secondViewController, animated: true)
    }


첫번째 버튼은 네비게이션 컨트롤러의 pushViewController를 사용했습니다. 

두번째 뷰컨트롤러인 SecondViewController의 인스턴스를 생성 -> 현재 네비게이션컨트롤러가 존재하는지 확인 -> 있으면 secondViewController를 네비게이션 뷰 스택에 push합니다. 그렇게 되면 두번째 뷰컨트롤러가 화면 상 띄워집니다.

 

    @objc func secondButtonPressed(_: UIButton) {
        print("pushViewController -> thirdView")
        let thirdViewController = ThirdViewController()
        navigationController?.pushViewController(thirdViewController, animated: true)
    }


두번째 버튼은 첫번째 버튼과 기능은 동일합니다. 다만, 세번째 뷰 컨트롤러로 이동을 합니다. 

세번째 뷰컨트롤러인 ThirdViewController의 인스턴스를 생성 -> 현재 네비게이션컨트롤러가 존재하는지 확인 -> 있으면 thirdViewController를 네비게이션 뷰 스택에 push 

 pushViewController(UIViewController, animated:)는 특정 뷰컨트롤러를 네비게이션 스택에 쌓아주어 해당 뷰컨트롤러로 화면전환을 시켜주는 메서드입니다.

 

secondViewController의 버튼이벤트입니다. 첫번째 버튼의 이벤트는 앞서 설명한 내용으로 생략하겠습니다.

앞서 말했듯이 네비게이션 스택이 쌓이고 빠지는 스택방식으로 화면전환이 가능한데요. push가 있다면 pop도 있겠죠?

 

    @objc func secondButtonPressed(_: UIButton) {
        print("popViewController -> firstView")
        navigationController?.popViewController(animated: true)
    }


SecondViewController의 두번째 버튼 이벤트는 이전 뷰컨트롤러인 firstViewController로 돌아가는 기능
입니다. 

popViewController(animated:)는 현재 뷰를 메모리 상 제거 하고 이전 뷰로 돌아가게 해줍니다. 네비게이션 스택을 한번 "pop" 해주는 메서드입니다. 

 

 

ThirdViewController의 버튼이벤트입니다. 

이번에는 또다른 네비게이션컨트롤러의 기능 두가지를 사용해 봤습니다. 

 

    // MARK:- ThirdView Button Event
    @objc func firstButtonPressed(_: UIButton) {
        print("popToViewController -> viewControllers[0]")
        guard let firstViewController = self.navigationController?.viewControllers[0] else { return }
        navigationController?.popToViewController(firstViewController, animated: true)
    }


첫번째 버튼은 네비게이션 스택 특정 인덱스를 접근하여 특정 뷰컨트롤러로 이동하는 기능을 사용했습니다. 

네비게이션컨트롤러는 viewControllers 라는 뷰컨트롤러 배열을 가집니다.배열을 접근해서 네비케이션스택 내 특정 위치로 이동을 할 수 있는 것인데요. viewControllers[0]은 네비게이션컨트롤러의 rootViewController가 되겠습니다. 네비게이션 스택 상 맨 처음 쌓였던 뷰컨트롤러가 rootViewController입니다. 

네비게이션컨트롤러의 viewControllers[0]가 있는지 옵셔널 바인딩(guard let)으로 확인 후, 네비게이션컨트롤러의 popToViewController(UIViewController, animated:)를 사용했습니다. 

위의 코드가 작동하면 viewControllers[0], rootViewController로 이동하되 그 보다 앞서 쌓여 있는 스택(뷰컨트롤러)는 전부 pop처리가 됩니다. 

만약 first,second,third 세개의 뷰컨트롤러가 네비게이션 스택에 쌓여있는 상태라면 second,third 뷰컨트롤러는 pop처리가 되고, firstViewController만 남아있게 되는 것입니다. 

✓ popToViewController(UIViewController, animated:)는 네비게이션 스택 내 특정 뷰컨트롤러로 이동 할 수 있게 해주는 메서드입니다. 해당 뷰컨트롤러 위에 쌓여있던 뷰컨트롤러 스택는 전부 해제됩니다.

 

    @objc func secondButtonPressed(_: UIButton) {
        print("popToRootViewController -> rootViewController")
        navigationController?.popToRootViewController(animated: true)
    }


ThirdViewController의 두번째 버튼 이벤트는 popToRootViewController입니다. 말그대로 rootViewController로 이동하는 것
입니다. 이 또한 rootViewController를 제외한 모든 viewController 스택은 헤제됩니다. popToRootViewController는 순전히 rootViewController로 이동하는 것이기에 별도의 뷰컨트롤러 인자값이 필요없지요. 그러므로 animated: 인자값을 통해 애니메이션처리 유무만 설정해주면 됩니다.

✓ popToRootViewController(animated:)는 네비게이션 스택의 rootViewController로 이동시켜줍니다. rootViewController를 제외한 뷰컨트롤러 스택은 "pop"되어 사라집니다.

오늘은 이렇게 스토리보드없이, 코드를 통해 네비게이션컨트롤러의 화면전환 관련 기본적인 기능을 확인해 보았습니다. 질문이나 지적사항 환영하며, 시뮬레이션 영상을 끝으로 포스팅 마칩니다

지금까지 네비게이션컨트롤러의 기본 화면전환 기능 코드구현하는 방법을 설명해봤습니다. 즐거운 하루되세요 ^-^//

 

 

 

네비게이션컨트롤러 화면전환 예제 실행 영상


 

 

 

 

 

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함