궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFTUI/View layout

SwiftUI : NavigationView / NavigationLink

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

 

 

NavigationView 는 SwiftUI의 가장 중요한 구성 요소 중 하나입니다. 화면을 쉽게 PushPop할 수 있으며, 사용자에게 명확하고 계층적인 방식으로 정보를 제공할 수 있습니다

NavigationView

NavigationView를 사용하려면 다음과 같이 항목을 감싸야합니다.

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!")
        }
    }
}

NavigationView는 최상위에 위치해야 하지만, TabView내에서 사용하는 경우에는 NavigationViewTabView 내에 있어야 합니다.

// 옳은 방법
NavigationView {
    Text("Hello, World!")
        .navigationBarTitle("Navigation")
}

//잘못된 방법
NavigationView {
    Text("Hello, World!")      
}
 .navigationBarTitle("Navigation")

TIP
 
 

NavigationView내에서 navigationBarTitle()를 사용할 수 있으며, 뷰 바깥쪽에서 사용하지 않아도 됩니다. 또한  displayMode parameter 를 사용하여 커스터마징을 할 수 있습니다. 

displayMode

.large 옵션은 내비게이션 스택의 최상위 보기에 유용한 큰 제목을 표시합니다.

.inline 옵션은 내비게이션 스택의 2 차, 3 차 또는 후속 보기에 유용한 작은 제목을 표시합니다.

.automatic 옵션은 기본값이며 이전에 사용한 View를 사용합니다.

.navigationBarTitle("Navigation")  //기본값에 .automatic 가 포함 되어 있다.
.navigationBarTitle("Navigation", displayMode: .inline)

NavigationLink

NavigationLink(destination: Text("String"))

SwiftUINavigationViewView의 맨 위에 NavigationBar를 표시하지만 다른 작업도 수행합니다.

 

Viewview stack에 푸시할 수 있습니다. 이것은 iOS view의 가장 기본적인 형태입니다. 예를 들어 WIFI를 탭 하면 설정으로 들어가져서 WIFI 목록을 볼 수 있거나, 연락처에서 이름을 탭 하면 메시지를 보내는 것과 같습니다.

 

TextViewNavigationView래핑하고 제목을 지정하면 다음과 같은 결과가 나타납니다.

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
            }
            .navigationBarTitle("SwiftUI")
        }
    }
}

→ 기본적인 NavigationView 형태.

 

화면을 보면 텍스트의 Hello Wolrd 에 아무런 변화가 없이 단지 텍스트로 보이죠? 이제 헬로월드를 클릭하면 새로운 탭으로 이동하는 코드를 작성해 봅시다!

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: Text("Detail View")) {
                    Text("Hello World")
                }
                
            }
            .navigationBarTitle("SwiftUI")
        }
    }
}

→ 이제 화면에 Hello World부분을 탭할 수 있게 바뀌고 그것을 누르면 Detail View 로 이동할 수 있습니다. 하지만 여기서 의문점이 있습니다.

 

Sheet()NavigationLink차이점이 무엇일까?

 

NavigationLinktopic을 더 자세히 살펴보는 것처럼 사용자가 선택한 것에 대한 세부 정보를 보여 줍니다.

sheet()는 설정 또는 작성 창과 같은 관련 없는 내용을 표시하는 데 사용됩니다.

List 와 NavigationLink

List에서 row in 하여 Navigationdestination: Textrow를 추가해주고, Text에 도 row를 할당해줍니다.

        NavigationView {
            List(0..<100) { row in
                NavigationLink(destination: Text("Detail \(row)")) {
                    Text("Row \(row)")
                }
                
            }
            .navigationBarTitle("SwiftUI")
        }

View를 추가하여 NavigationLink에 연동

만약 동전의 앞과 뒤 중에 골라야 하는 버튼이 있고, 그 버튼을 누르면 "    를 선택하셨습니다" 와 같은 텍스트를 보여주고 싶으면

아래와 같이 ContentView 바깥에 또 다른 View를 생성해 주면 됩니다.

struct ResultView: View {
    var choice: String
    
    var body: some View {
        Text("\(choice)을 선택하셨습니다. ")
    }
}

이제 ContentViewNavigationViewText, NavigationLink등을 추가해줍니다.

import SwiftUI

struct ResultView: View {
    var choice: String
    
    var body: some View {
        Text("\(choice)을 선택하셨습니다. ")
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack(spacing: 30) {
                Text("당신은 동전을 던질것입니다\n앞면 과 뒷면 중에 하나를 선택해 주세요.")
                    .multilineTextAlignment(.center)
                
                
                NavigationLink(destination: ResultView(choice: "앞면")) {
                    Text("앞면을 선택하셨습니다.")
                }
                
                NavigationLink(destination: ResultView(choice: "뒷면")) {
                    Text("뒷면을 선택하셨습니다.")
                }
            }
            .navigationBarTitle("Navigation")
        }
    }
}

 

Image 와 NavigationLink

아래 코드와 같이 NavigationLink 내에서 Image를 넣어주면 자동으로 텍스트와 모든 것을 파란색으로 설정하게 됩니다.

이것은 때때로 유용할 수 도 있지만, 그렇지 않은 경우가 더 많이 있습니다. 

        NavigationView {
            NavigationLink(destination: Text("Second View")) {
                Image("원하는 사진")
            }
            .navigationBarTitle("Navigation")
        }

 만약 사진을 정상적으로 보여주고 싶다면 .renderingMode(.original) 를 Image 밑에 추가해 주면 됩니다.

        NavigationView {
            NavigationLink(destination: Text("Second View")) {
                Image("원하는 사진")
                    .renderingMode(.original)
            }
            .navigationBarTitle("Navigation")
        }

이것의 대안으로는 PlainButtonStyle()과 함께 buttonStyle() 수정자를 사용할 수 있습니다.

        NavigationView {
          NavigationLink(destination: Text("Second View")) {
              Image("원하는 사진")
          }
          .buttonStyle(PlainButtonStyle())
          .navigationTitle("Navigation")
        }

혹은 button으로 만들어 줄 수 있겠죠.

        NavigationView {
            Button {
                // your action here
            } label: {
                Image("card")
                    .resizable()
                    .scaledToFit()
            }
            .buttonStyle(PlainButtonStyle())
          
          .navigationTitle("Navigation")
        }

Environment presentationMode

NavigationLink view에서 Back버튼을 hidden으로 해놓고 따로 버튼을 만들어서 그 버튼을 누르면 메인화면으로 돌아갈 수 있도록 만들어 줄 수도 있습니다. 이것을 사용하기 위해서는 EnvironmentpreseontationMode를 사용 하면 됩니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView(.vertical, showsIndicators: false) {
                Text("some")
                Text("some")
                Text("some")
            }
            .navigationBarTitle("네비게이션")
            .navigationBarItems(
                trailing:
                    NavigationLink(
                        destination: secondView(),
                        label: {
                            Image(systemName: "person.fill")
                                .foregroundColor(.red)
                        })
            )
        }
    }
}
struct secondView: View {
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        ZStack(alignment: .topLeading) {
            Color.yellow.ignoresSafeArea()
                .navigationBarBackButtonHidden(true)
                .navigationBarHidden(true)
            
            Button(action: {
                presentationMode.wrappedValue.dismiss()
            }, label: {
                Image(systemName: "xmark")
                    .imageScale(.large)
                    .padding()
            })
            .accentColor(.white)
        }
    }
}

NavigationBarItems /  NavigationBarTitle

위에서 나왔던 navigationBarTitle 의 종류에 대해서 먼저 알아보겠습니다.

        NavigationView {
            Text("서근 개발블로그")
                .navigationBarTitle("스위프트UI", displayMode: .inline)
        }

automatic / inline / large 3가지가 있고, 기본값이 automatic 인거 같죠? 일단 inline을 먼저 사용해서 화면을 구성해보면,

여기에 NavigationBarItems을 추가해 봅시다.

leading / trailing이 있네요. 이제 navigationBarTitle에 아이템을 추가해서 오른쪽, 왼쪽 버튼을 만들어볼게요.

        NavigationView {
            Text("서근 개발블로그")
                .navigationBarTitle("스위프트UI", displayMode: .inline)
                .navigationBarItems(leading:
                                        Button("왼쪽")
                                        { /*code*/  }
                                    ,trailing: Button("오른쪽")
                                        { /*code*/ } )

왼쪽에 버튼을 두 개 추가하고 싶을 땐?

        NavigationView {
            Text("서근 개발블로그")
                .navigationBarTitle("스위프트UI", displayMode: .inline)
                .navigationBarItems(leading:
                                        HStack {
                                            Button("서근")
                                                { /*code*/  }
                                            Button("블로그")
                                                { /*code*/ }
                                        },trailing:
                                            HStack {
                                                Button("구독")
                                                    { /*code*/ }
                                                Button("좋아요")
                                                    { /*code*/ }
                                            }
                )
            
        }

 

뭐.. 버튼이 기본적이지만, 텍스트를 주고 싶다면 가능은 합니다 :)

        NavigationView {
            Text("서근 개발블로그")
                .navigationBarTitle("스위프트UI", displayMode: .inline)
                .navigationBarItems(leading:
                                        Text("서근"),
                                    trailing:
                                        Text("블로그")
                )
        }

SF Symbols.navigationBarItems에 추가해보도록 하겠습니다. 

 

Image로 불러와주고 심볼 아이템을 resizable()해주고 frame()으로 크기를 조절해 주겠습니다.

struct DetailView: View {
    var body: some View {
        Text("서근 개발 블로그")
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("사이트")
                .navigationBarTitle(Text("홈"))
                .navigationBarItems(trailing: NavigationLink(destination: DetailView()){
                    Image(systemName: "paperplane.circle.fill").resizable()
                        .frame(width: 30, height: 30, alignment: .trailing)
                    
                }
            )
        }
    }
}

심볼 사이즈를 frame()으로 지정해줄 수 도 있지만 .font(.system(size: CGFloat)) 으로도 가능합니다.

        NavigationView {
            Text("사이트")
                .navigationBarTitle(Text("홈"))
                .navigationBarItems(trailing: NavigationLink(destination: DetailView()){
                    Image(systemName: "paperplane.circle.fill").font(.system(size: 30))
                }
            )
        }

Hidden

navigationBarHidden

이밖에도 필요에 따라 NavigationBar 또는 back 버튼을 숨길 수 있습니다.

NavigationView {
    HStack {
        Image(systemName: "person.fill")
        Text("서근 개발 블로그")
            
            .navigationTitle("NavigationBarHidden")
            .navigationBarHidden(true)
    }
}

navigationBarHidden 수식어 적용 과 미적용 비교

navigationBackButtonHidden

마찬가지로 back 버튼을 숨기려면 원하는 뷰 뒤에 코드를 추가해줘야 합니다.

 NavigationView {
    HStack {
        Image(systemName: "person.fill")
        Text("서근 개발 블로그")
            
            .navigationTitle("NavigationBarHidden")
            
            .navigationBarItems(trailing: NavigationLink(destination: Text("안녕하세요").navigationBarBackButtonHidden(true)) {
                Image(systemName: "star.fill").font(.title)
                
            }
            )
        
    }
 }

TIP
 
 

navigationBarBackButtonHidden 사용 주의사항
destination으로 가져온 뷰 바로 뒤에 navigationBarBackButton을 추가해줘야 합니다.

 


읽어주셔서 감사합니다🤟

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.