티스토리 뷰

macOS, iOS

[SwiftUI] Navigation

SweetDev 2021. 2. 25. 21:08

일단 볼게, 

 

1. navigation 만들기

2. custom backbutton 만들기

3. pop to root view 만들기

4. 코드로 navigation 실행하기

 

이렇게 4개 할 예정이다!

 

일단 나는 title이랑 navigationButton을 같이 쓰는 화면이 엄청 많아서, 미리 ViewModifier을 만들어 뒀다.

struct BackButtonAndTitle: ViewModifier {
  var title: String
  var backButtonAction: () -> ()

  func body(content: Content) -> some View {
    HStack {
      Button(action: { self.backButtonAction() }, label: {
      }).buttonStyle(BackButtonStyle())
      Text(title)
    }
  }
}

 

1. Navigation 만들기

Navigation 자체는 만드는 방법이 간단하다. 

struct MainView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: DetailView()) {
                Text("여기 누르면 detailView로")
            }
        }
    }
}
struct DetailView: View {
    var body: some View {
        VStack() {
            Text("detailView임")
        }
        .navigationBarTitle("뒤로가기")
    }
}

ㅇㅎ root가 될 부분에다가 NavigationView{NavigationLink()} 로 만들어주면 되는구나

 

2. custom backbutton 만들기

detailView에 다음과 같은 작업을 해주면 된다. 

struct DetailView: View {
  @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
  var body: some View {
      self.modifier(BackButtonAndTitle(title: "이메일 로그인", backButtonAction: {
        self.presentationMode.wrappedValue.dismiss()
      })
    }
    .navigationBarBackButtonHidden(true)
}

navigationBarBackButton을 hidden시켜주고, backbuttonAction을 따로 달아주면 된다.

 

* 단점: 왼쪽으로 스와이프 해서 뒤로가기가 안된다...ㅠ 다행히 내 프로젝트에서는 필요가 없었다. 

 

3. popToRootView 구현하기

RootPresentationMode라는 extension을 만드는 방법이다. 

 

struct RootPresentationModeKey: EnvironmentKey {
  static let defaultValue: Binding<RootPresentationMode> = .constant(RootPresentationMode())
}

extension EnvironmentValues {
  var rootPresentationMode: Binding<RootPresentationMode> {
    get { return self[RootPresentationModeKey.self] }
    set { self[RootPresentationModeKey.self] = newValue }
  }
}

typealias RootPresentationMode = Bool

public extension RootPresentationMode {
  mutating func dismiss() {
    self.toggle()
  }
}

 

struct ContentView: View {
    @State private var isActive : Bool = false
    var body: some View {
        NavigationView {
            VStack {
                Text("Root")
                NavigationLink(destination: ContentView2(), isActive: self.$isActive )
                { Text("Push") }
                    .isDetailLink(false)
            }
            .navigationBarTitle("Root")
        }
        .navigationViewStyle(StackNavigationViewStyle())
        .environment(\.rootPresentationMode, self.$isActive)
    }
}
struct ContentView2: View {
    @State private var isActive : Bool = false
    @Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
    @Environment(\.rootPresentationMode) private var rootPresentationMode: Binding<RootPresentationMode>
    var body: some View {
        VStack {
            Text("Two")
            NavigationLink(destination: ContentView3(), isActive: self.$isActive)
            { Text("Push") }
                .isDetailLink(false)
            Button (action: { self.presentationMode.wrappedValue.dismiss() } )
            { Text("Pop") }
            Button (action: { self.rootPresentationMode.wrappedValue.dismiss() } )
            { Text("Pop to root") }
        }
        .navigationBarTitle("Two")
    }
}
struct ContentView3: View {
    @State private var isActive : Bool = false
    @Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
    @Environment(\.rootPresentationMode) private var rootPresentationMode: Binding<RootPresentationMode>
    var body: some View {
        VStack {
            Text("Three")
            NavigationLink(destination: ContentView4(), isActive: self.$isActive)
            { Text("Push") }
                .isDetailLink(false)
            Button (action: { self.presentationMode.wrappedValue.dismiss() } )
            { Text("Pop") }
            Button (action: { self.rootPresentationMode.wrappedValue.dismiss() } )
            { Text("Pop to root") }
        }
        .navigationBarTitle("Three")
    }
}

 

4. 코드로 navigation 실행하기

NavigationLink의 isActive를 사용해서 구현한다. 

NavigationLink(destination: SNSRegisterScene(), isActive: self.$isKakaoTalkActive) {
            EmptyView()
          }.isDetailLink(false)

이렇게 해놓고, 다른 함수를 통해서 isKakaoTalkActive변수를 true로 바꿔주면 된다. true로 바뀌는 순간 Navigation이 자동으로 실행된다. 

EmptyView()는 저거를 보여주는 버튼같은게 없다는 소리이다. 

 

또, 화면을 닫을 때 자동으로 isActive를 false로 바꿔준다. 내가 따로 바꿔줄 필요는 없다!!

 

** 문제 **

나는 저 destination: SNSRegisterScene()이 당연히 navigationLink가 실행될때 생성될거라고 생각했는데, 저 scene이 생길때 미리 객체를 만들어서 로드를 해둔다. 클릭시 화면이 빨리 보이는 장점이 있지만, 나는 그런 기능은 필요 없었다... 메인 화면에 달린 네비게이션 링크가 너무 많아서 앱이 켜지는데 오래걸리는것처럼 느껴졌다. 

 

따라서 다음과 같은 코드를 추가해줬다. (출처 )

/// NavigationLink에 의해서 viewModel init()이 콜되어서 main진입시 너무 오래걸리는 문제를 해결하기 위한 view
struct NavigationLazyView<C: View>: View {
  let build: () -> C
  init(_ build: @autoclosure @escaping () -> C) {
    self.build = build
  }

  var body: C {
    build()
  }
}

 

 

 

[참고]

github.com/Whiffer/SwiftUI-PopToRootExample/blob/master/SwiftUI-PopToRootExample/ContentView.swift

'macOS, iOS' 카테고리의 다른 글

[SwiftUI] dark mode disable하기  (0) 2021.02.26
[iOS] swift의 mutating은?  (0) 2021.02.26
[iOS] 네이버 간편로그인(네아로) for SwiftUI  (2) 2021.02.25
[iOS] device 정보 가지고 오기  (0) 2021.02.25
[SwiftUI] ButtonStyle  (0) 2021.02.23
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
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 31
글 보관함