Overview
우리가 사용하는 어플리케이션이 하나의 화면에서 동작하는 경우가 흔한 일이 아니다. 다수의 앱은 다양한 형태의 데이터를 보여주기 위해 다양한 화면을 갖고 있으며 각 화면의 뒤에는 개별적인 ViewController 인스턴스가 동작하고 있다. 프로젝트를 구현하면서 ViewController 간의 화면 전환 기능을 활용해야 하는 경우가 많이 있었는데 오늘 간단하게 정리해보고 넘어가보려고 한다.
- Segue 에 존재하는 타입에 대해 알아본다.
- 네비게이션 컨트롤러에서 서로 다른 화면간에 segue 를 어떻게 생성하는지 배워본다.
- navigation 계층을 활용한 좀더 복잡한 UI를 구성해본다.
Segue
segue 는 하나의 View Controller 에서 다른 View Controller 로의 화면 전환을 정의한 것이다. 특정 버튼이나 테이블 뷰 행을 터치하면 호출되며 결과적으로 새로운 ViewController 가 등장하게 된다. 인터페이스 빌더에서 outlet 혹은 action 을 정의하는 방식처럼 컨트롤 드래그를 활용하여 시작 지점과 끝나는 지점을 이어주는 방식으로 정의할 수 있다.
화면 전환에서 더 나아가, segue 는 ViewController 가 어떤 방식으로 보여질지 결정할 수 있다. (Presentation Method) 공통적인 방식 중 하나로 Modal 방식으로 보여주는 동작이 있는데 이전 화면의 위에 새로운 ViewController 를 올려두는 방식으로 동작한다. 작은 화면에서 modal 프레젠테이션을 사용하면 항상 전체화면을 체우는 방식으로 동작하지만 대화면 장치를 위한 UI에 적용하기 위해 개발자는 modal 프레젠테이션 방식을 popover, form sheet, 전체 화면 보기로 사용자화시킬 수 있다.
새로운 ViewController가 modally 하게 등장할 때 , unwind segue 를 통해 현재 화면을 dismiss 시키고 이전 화면으로 돌아갈 수 있도록 구현할 수 있다.
Segue 를 통한 화면 전환 예시 #1
위에 보이는 화면에서는 서로 다른 배경색을 갖는 Scene 이 존재한다. 각 Scene 의 중앙에는 다음 화면으로 전환할 때 사용할 버튼이 위치하고 있다.
화면 전환을 위해 버튼으로 부터 컨트롤 드래그 해서 원하는 목적지의 scene에 마우스를 올려두면 대상 화면이 자신도 적용될 수 있음을 알리고자 푸른 빛으로 변화하며 화면 전환 동작 방식을 결정할 수 있도록 popover 창을 띄워준다.
지금과 같은 상황에서 선택지로 Present Modally, Show가 눈에 띄게 되는데 Present Modally 를 선택하면 빨간색 ViewController 위로 하단부터 상단으로 슬라이드 애니메이션이 동작하며 화면을 덮게 된다. 이런 애니메이션 동작은 iOS 기본 메일 앱에서 새로운 메일을 작성하는 창이 보이는 원리와 유사하다. 현재 눈앞에 보이는 popover 창 외에도 identity 인스펙터에서 세부 설정을 변경해줄 수 있다.
노란색 scene 과 초록색 scene 사이의 화면 전환을 정의할 때에도 같은 방식을 사용하면 된다. 여기서 주목할 점은 빨간색 VoewController 에서는 사용자가 UIViewController를 확장시킨 ViewController 를 선언해주었지만 나머지 노란색과 초록색 scene 에서는 generic 하게 사용되는 UIViewController 를 사용하는 방식으로 구현되었는데 두 구현 방식의 차이가 이전 화면으로 돌아가도록 도와주는 unwindsegue를 구현할 때 명확하게 보인다.
물론 사용자가 modally하게 띄어진 view 를 화면 아래로 쓸어내리면서 dismiss 시킬 수도 있지만 가장 이상적인 방법은 사용자가 이전 화면으로 돌아갈 수 있는 버튼을 제공하는 것이다. unwindSegue 는 개발자가 짧은 순서의 segue를 선언했을때, segue 가 새로운 화면으로의 전환을 정의하고 있다면 unwindsegue는 현재 화면으로 부터 이전에 보여졌던 화면으로 되돌아가는 전환을 구현하는 것이다. 이 기능을 사용하려면 대산 ViewController 소스 코드 파일에 다음과 같은 소스 코드를 추가해줘야 한다.
@IBAction func unwindToRed(unwindSegue: UIStoryboardSegue) { }
메서드 이름은 자유롭게 선언해줄 수 있지만 반드시 UIStoryboardSegue 하나만을 파리미터로 받아와야 한다. 처음에 이 방식이 좀 이상해보일 수 있다. 위와 같은 액션 함수를 어느 ViewController에 구현해둔다는 의미는 인터페이스 빌더에게 해당 scene 이 unwind segue 하는데 유효한 scene 이라는 점을 알려주는 것과 동일하다. 이번 구현에서는 해당 메서드에 세부적인 동작을 명시하지는 않았지만 내부에 세부적인 구현을 포함 시켜서 목적지 ViewController 에게 어떻게 자료를 넘겨줄지 세부적인 구현을 해볼 수 있다.
한번 unwindsegue 를 붉은색 화면의 ViewController에 등록시킨 후에 파란색 화면의 버튼이 클릭되면 붉은색 화면의 unwindsegue를 통해 이전 화면으로 돌아가도록 구현해보자! 붉은색 화면의 ViewController에 위와 같은 코드를 선언해준 후에 파란색 scene dock 에 있는 Exit 으로 버튼으로부터 컨트롤 + 드래그 하여 segue 를 선언해줄 수 있다.
Navigation Controller
Human Interface Guideline 에도 계층적인 탐색 방식과 modally 하게 화면을 보여주는 것 사이에 기준을 화면에서 보며주는 맥락을 통해 잡아주는 경우를 본적이 있다. Modal Segue의 경우 앱에서 새로 보여줘야 할 화면의 맥락이 현재 보여주고 있는 화면의 맥락과 서로 다른 경우에 활용된다. 지속적으로 언급되는 예시로서 애플 메일 앱에서 메일을 작성하는 화면과 메일을 보여주는 화면 사이에 modal을 통한 화면 전환이 발생한다는 예시가 자주 보이고 있으며 위에서 Segue 를 통해 구현한 화면 전환은 어떠한 presentation 방식을 선택하더라도 모두 동일하게 Modally 한 방식으로 화면 전환 동작을 구현시켜주고 있다.
그렇다면 화면에서 보여주는 데이터의 맥락이 계속 이어지는 경우에는 어떻게 구현시켜줘야할까? 비슷한 예시로서 iOS 에서의 설정앱을 떠올려볼 수 있을 것이다. 설정앱 화면에 보이는 테이블 뷰의 셀을 클릭하면 해당 셀이 의미하는 세부적인 화면으로 들어가게 되는데 이때 오른쪽에서 왼쪽 방향으로 새로운 화면이 현재 창을 덮어주는 애니메이션이 보이며 마치 시각적으로 스택에 화면을 쌓아나가는 방식으로 동작한다.
왼쪽 상단에 위치한 뒤로가기 버튼을 클릭하거나 좌측에서 우측으로 드래그해서 현재 눈에 보이는 화면을 dismiss 하고 이전 화면으로 돌아갈 수 있는데 이 동작이 마치 스택에서 자료를 pop 하는 것과 동일한 구조로 이뤄진다.
Navigation Controller 는 View Controller 의 스택을 관리해주고 연관된 View 들 사이에 탐색 과정이 이뤄질 때 애니메이션을 제공해주는 역할을 담당한다. 위에서 구현했던 ViewController 들을 Navigation Controller를 활용하여 관리하려면 ViewController 를 NavigationController 에 embed in 시켜주면 된다. 인터페이스 빌더 우측 하단에 있는 embed in 버튼을 활용해도 되고 Xcode 메뉴바에서 “Editor > Embed In > Navigation Controller” 를 통해 구현하는 방법도 있는데 그냥 편한 방식 사용하면 된다.
Segue가 시작될 가장 root 지점을 선택한 후에 navigation controller 를 삽입하면 이전과 비교해서 몇가지 주목할만한 차이점을 볼 수 있을 것이다.
- segue 에서 화면 전환 방식을 정의해줄 때, navigation controller 를 적용하기 전에는 무조건 모든 창이 Modally 하게 띄어줬지만 navigation controller가 적용된 후에는 스택에 쌓아가듯이 Push 를 통해 화면 전환을 구현하고 있다.
- Dismiss 버튼을 클릭하면 빨간색 ViewController로 돌아가게 되는데, 화면을 dismiss 시키는 대신 Pop을 활용하여 전환시키고 있다.
- 각 View의 상단에는 투명빛의 navigation bar 가 위치하고 있는데, 타이틀과 추가적인 버튼 및 뒤로가기 버튼을 위한 공간을 제공하고 있다.
- 인터페이스 빌더 부분을 보면 Document Outline 에서 navigation bar 를 포함하고 있다.
Navigation Bar
네비게이션 컨트롤러가 제공해주는 가장 명백한 기능은 navigation bar 기능일 것이다. 화면 상단에서 나타나며 타이틀이나 버튼 아이템 같은 것을 표현해줄 수 있다.
NavigationItem
모든 UIViewController는 navigationItem 을 갖고있는데 이를 통해 navigationBar를 사용자화 시킬 수 있다. 이전 스텝에서 navigation controller를 추가해줬다면, 인터페이스 빌더는 자동으로 붉은색의 root view controller에 navigationItem 을 추가해준다. navigationItem의 Attribute 를 수정하여 타이틀이나 back 버튼에 보여질 글자를 수정할 수 있다.
Xcode 의 오브젝트 라이브러리에서 bar button item 을 navigationItem으로 추가해줄 수 있는데 초록색 화면에 있었던 버튼을 BarButton 으로 구현해볼 수도 있다. bar button은 네비게이션 바 뿐만 아니라 Tool Bar 에서도 사용할 수 있다고 한다.
bar button을 선택하면 Attribute 인스펙터를 통해 버튼에 대한 세부 정보를 설정해줄 수 있다. 예를 들어 system Item 버튼 속성을 바꿔서 버튼의 모양도 바꿔줄 수 있고 틴트 색상을 바꿔서 버튼의 색상도 변경해줄 수 있다.
Large Title
설정 앱의 네비게이션 바 타이틀을 보면 큰 글씨로 보이는 경우가 있다. navigation controller 에서도 이 기능을 활성화 시켜줄 수 있다! navigation controller에서의 navigation bar 객체를 선택한 후에 Attribute inspector 에서 prefers large titles를 선택해주면 된다.
각 화면에서도 개별적으로 navigation bar를 선택하여 large title을 설정해줄 수 있지만 관습적으로는 첫번째 root view controller에서만 large title을 사용하고 이후에 화면에서는 smaller 타이틀을 사용하는 경우가 많다고 한다.
실제로 Navigation 과정 중에서 root view controller 다음의 view controller 를 선택해서 smaller 타이틀을 설정해줄 수 는데 그 이후에 모든 ViewController에도 동일하게 동작한다.
Pass Information
기본앱 중에서 주소록 앱을 생각해보면 테이블 뷰에 있는 특정행을 선택하면 해당 인물에 대한 세부적인 주소록 정보가 보인다. 이 과정의 뒤쪽에서 무슨 동작이 발생하고 있는지 탐구해보자!
빨간색 화면에 있는 TextField에 담긴 데이터를 노란색 뷰 컨트롤러에 전달하는 것이 목표이다. segue 는 identifier와 destination 정보를 담고 있는데 identifier 는 segue를 식별하기 위하여 붙여준 이름이며 destination 은 세그가 가리키는 목적지 ViewController를 의미한다. 여기서 destination ViewController 에 있는 세부 프로퍼티에 접근하려면 다운 캐스팅을 해줘야 할 수 있다.
Programmatic Segues
ViewController Scene Dock에서 다른 화면으로 드래그 하면 generic segue 를 생성해줄 수 있다. 이 세그에 식별자를 붙여주어서 상황에 따라 세그를 실행시켜줄 수 있는데 어떻게 동작하는지 생각해보고자 한다!
performSegue 메서드는 특정 identifier를 가진 segue를 코드를 통해 수행시켜준다. identifier는 스토리보드에서 identity 인스펙터를 통해 segue에 지정해준 식별자이다. 필요한 경우 sender 인자 부분에 어떤 객체가 segue를 수행시켰는지 담아줄 수 있기는 한데 불필요하다면 nil 을 넣어주는 것도 가능하다!
' Apple > iOS Dev Challenges' 카테고리의 다른 글
[Challenge] GCD (0) | 2021.12.17 |
---|---|
[Challenge] 간단한 네트워크 통신에 대해 탐구해보자! (0) | 2021.12.16 |
[Challenge] iOS 13 이후의 Scene 톱아보기! (0) | 2021.11.25 |
[iOS - Laboratory] iOS 앱의 Life Cycle 추적해보기 (iOS 12와 이전 버전) (0) | 2021.11.25 |
[iOS - Laboratory] iOS 앱의 실행 흐름 추적해보기 (0) | 2021.11.24 |