본문 바로가기
iOS/SwiftUI

NavigationView, NavigationLink(Pop to Root) 원하는 페이지로 이동하기

by 지금갑시다 2022. 5. 5.

iOS개발을 하면서 필요한 기능이 있을 때마다 구글링을 해서 찾아 공부하는 편입니다. 

 

왠만한 정보들은 구글링을 하다보면 거의 다 나오는데, 이번에 제가 원하던 기능을 어떻게 쳐야 할 지 몰라 처음부터 당황을 조금 했죠.

 

그렇게 원하던 키워드를 찾았는데, 바로 'NavigationLink Pop to Root' 였습니다.

 

저와 비슷하게 구글을 돌아다니다 오신 분들에게 오아시스와 같은 블로그가 될 수 있게 글작성을 해보도록 하겠습니다.

 

제가 도움 받았던 Reference를 먼저 작성하겠습니다.

 

https://synapsis9.tistory.com/entry/SwiftUI-Navigation-View-To-Root-네비게이션-뷰-관리하기?category=1027197 

 

SwiftUI Navigation View To Root - 네비게이션 뷰 관리하기

뷰를 만들다 보면 뷰 1에서 뷰 2로 이동하고, 뷰 2에서 뷰 3으로 이동하는 등 그 깊이와 복잡도가 올라갈 수밖에 없다. 이번에는 swiftUI에서 1->2->3->4 뷰로 이동했다고 가정할 때, 다시 뷰 1(root view)

synapsis9.tistory.com

https://stackoverflow.com/questions/57334455/swiftui-how-to-pop-to-root-view

 

SwiftUI: How to pop to Root view

Finally now with Beta 5 we can programmatically pop to a parent View. However, there are several places in my App where a View has a "Save" button that concludes a several step process and returns ...

stackoverflow.com

 

사실 위의 개념을 이해하기 위해서는 @State@Binding에 대해서는 알고 계셔야 합니다.

 

혹시 위의 개념을 정확하게 모르고 계신다면! 두 개념 먼저 구글링을 해보시면 좋을 것 같아요!

추후에 저도 더 정확히 공부해보고 블로그에 글 작성을 해보겠습니다.

 

자! 이제 Pop to Root 개념으로 넘어가 볼까요?

 

먼저 Pop to Root는 어떤 개념일까요.

 

화면에서 목록을 선택하여 넘어가게 될때 SwiftUI에서는 NavigationLink를 이용하여 목적지인 파일로 링크를 해주어 넘어갈 수 있게 해줍니다.

 

그럼 그 목적지인 파일이 뷰로 나오게 되고 왼쪽 상단에는 뒤로가기 버튼이 생기게 되죠.

왼쪽 상단의 Back표시

 

왼쪽 상단의 Back을 누르게 되면 이전화면으로 돌아갈 수 있겠죠.

 

근데 저는 위에서 1->2->3->4 페이지로 넘어가는 건 알겠고, Back버튼을 눌러서 뒤로 가는 것 역시 알겠는데..

 

도대체 4페이지에서 1페이지로는 어떻게 바로가고? 4페이지에서 2페이지로는 어떻게 가는 거란 말입니까?

 

분명히 어플들을 써보면, 어떤 선택을 하고 나서 아무리 몇번의 클릭이 있고, 그 깊이가 깊어진 것 같아도 홈화면으로 바로 돌아오는 경험을 해본 적이 있는데, 막상 구현을 하려니까 모르겠는 겁니다.

 

그래서 알고자 하는 기능이 바로! 'NavigationLink를 활용한 Pop to Root'입니다.

 

1->2->3->4 페이지 구성일때, 4->1 혹은 4->2 혹은 3->1 로 갈 수 있는 기능이라는거죠.

 

먼저 메인 페이지를 봐볼까요?

 

메인 페이지 (1페이지)

메인페이지 (1페이지)

struct PopToRootPrac: View {
    @State var goToPage1:Bool = false
    
    var body: some View {
        NavigationView {
            VStack(spacing: 50) {
                Text("This is Page 1")
                
                Button(action: {
                    goToPage1.toggle()
                }, label: {
                    Text("Go to Page 2")
                })
                .background(NavigationLink(destination: Page2(goToPage1: $goToPage1), isActive: $goToPage1, label: {EmptyView()}).isDetailLink(false)
                )
            }
        }
    }
}

 

1페이지의 코드입니다.

@State 를 이용해서 다음페이지에 1페이지가 열려있다 라는 값을 전해주기 위함이고, 

 

특이한 점으로는 NavigationLink로 바로 연결해주지 않고, Button의 background로 이용해 주었다는 건데,

 

이는 NavigationLink의 isActive를 사용해서 이동시켜주기 위함입니다.

 

따라서 Button이 있으므로, label은 EmptyView()로 주었고, 

 

가장 뒤의 isDetailLink(false)는 네비게이션링크가 앞뒤로만 움직일 것이 아니라, 가고 싶은 페이지로 이동하고 싶기 때문에 이를 가능하게 해주는 코드입니다.

 

버튼을 눌러서 2페이지로 이동해 볼까요?

 

 

2페이지

2페이지

2페이지입니다. 1페이지와 코드블럭도 굉장히 유사하여 설명을 생략합니다.

코드를 보시면 이해가 가실 겁니다.

다른점으로는 1페이지의 goToPage1 값을 받아와야 하기 때문에 @Binding 값이 존재합니다.

 

struct Page2:View{
    @Binding var goToPage1:Bool
    @State var goToPage2:Bool = false
    
    var body: some View{
        VStack(spacing: 50){
            Text("This is Page2")
            
            Button(action: {
                goToPage2.toggle()
            }, label: {
                Text("Go to Page3")
            })
            .background(NavigationLink(destination: Page3(goToPage1 : $goToPage1, goToPage2: $goToPage2), isActive: $goToPage2, label:{EmptyView()}).isDetailLink(false))
        }
    }
}

 

Page2에서도 역시 @State 값을 만들어 줬는데, 이는 2페이지가 열여있음을 다른 뷰에 알리기 위해서 입니다.

 

버튼을 눌러 3페이지로 가봐요!

 

3페이지

 

3페이지

3페이지부터는 조금 다른 점이 있는데요, 위에서 버튼을 보면 아시다시피

 

1페이지로 Popup!, 2페이지로 Popup!, 그리고 4페이지로 넘어가는 액션이 있습니다.

 

우리가 궁금해서 공부할 Pop up to Root는 1페이지로 바로 가는 것을 의미하고, 2페이지로 Pop up 하는 것은 이해를 돕기위해서 넣어 놓았습니다.

 

코드 블럭을 한번 먼저 볼까요?

 

struct Page3:View{
    @Binding var goToPage1:Bool
    @Binding var goToPage2:Bool
    @State var goToPage4:Bool = false
    
    var body: some View{
        VStack(spacing: 50){
            Text("This is Page3")
            
            Button(action: {
                goToPage1.toggle()
            }, label: {
                Text("Go Back To Page1")
            })
            
            Button(action: {
                goToPage2.toggle()
            }, label: {
                Text("Go Back To Page2")
            })
            
            Button(action: {
                goToPage4.toggle()
            }, label: {
                Text("Go to Page4")
            })
            .background(NavigationLink(destination: Page4(goToPage1:$goToPage1, goToPage2:$goToPage2, goToPage4:$goToPage4), isActive: $goToPage4, label: {EmptyView()}).isDetailLink(false))
        }
    }
}

1페이지로 바로가는 우리가 원하는! 그 Pop to Root 버튼은 1페이지에서부터 @Binding해온 그 goToPage1 값을 토글해주어 바꾸어 주면 됩니다.

 

그렇게 된다면, 현재 있는 3페이지에서 goToPage1 값은 isActive에서 true인 상태였는데, 토글되어 false가 되어버리고, 자연스럽게 바뀐 goToPage1값의 @Binding으로 상위 뷰의 goToPage2가 false 가 되며, 1페이지로 돌아가게 되는 겁니다. 연쇄적으로 값이 변하여 순간적으로 메인으로 돌아오게 되는 것이죠.

 

위와 동일하게 3->2로 넘어가려면, 2페이지에의 isActive 값을 false로 바꾸어 주면 되죠.

 

따라서 위와 같은 코드가 나오게 된 것입니다.

 

4페이지에서는 1페이지로 가기, 2페이지로가기, 3페이지로 가기의 기능이 있는데요. 이는 한번 직접 해보시기 바랍니다! 

 

직접 해봐야 더 잘 이해가 될 수 있으니까요!

 

4페이지까지 완성한 코드는 

https://github.com/sunshiningsoo/SwiftUIDictionary/tree/main/SwiftUIDictionary/NavigationView/PopToRoot

 

GitHub - sunshiningsoo/SwiftUIDictionary

Contribute to sunshiningsoo/SwiftUIDictionary development by creating an account on GitHub.

github.com

여기에 있습니다!

 

 

이 글을 여기까지 본 당신은 이제! 페이지 이동을 자유롭게 구현해 볼 수 있게 되었을 겁니다ㅎㅎ

 

 

 

사실 위의 글에 부족한 점이 정말 많을 겁니다.

 

그래도 제가 이 글을 작성한 이유는 Pop to Root 관련 글이 한국어로 된 글들이 없어 조금이라도 도움이 되어보자 생각하여 작성해 보았습니다.

 

미흡한 점이 보이신다면 자유로운 피드백 감사히 받겠습니다.

 

감사합니다!