Show a new View from Button press Swift UI

前端 未结 2 1428
不知归路
不知归路 2020-12-10 19:11

I would like to be able to show a new view when a button is pressed on one of my views.

From the tutorials I have looked at and other answered questions here it seem

相关标签:
2条回答
  • 2020-12-10 19:12

    For simple example you can use something like below

    import SwiftUI
    
    struct ExampleFlag : View {
        @State var flag = true
        var body: some View {
            ZStack {
                if flag {
                    ExampleView().tapAction {
                        self.flag.toggle()
                    }
                } else {
                    OtherExampleView().tapAction {
                        self.flag.toggle()
                    }
                }
            }
        }
    }
    struct ExampleView: View {
         var body: some View {
            Text("some text")
        }
    }
    struct OtherExampleView: View {
        var body: some View {
            Text("other text")
        }
    }
    

    but if you want to present more view this way looks nasty

    You can use stack to control view state without NavigationView

    For Example:

        class NavigationStack: BindableObject {
            let didChange = PassthroughSubject<Void, Never>()
    
            var list: [AuthState] = []
    
            public func push(state: AuthState) {
                list.append(state)
                didChange.send()
            }
            public func pop() {
                list.removeLast()
                didChange.send()
            }
        }
    
        enum AuthState {
            case mainScreenState
            case userNameScreen
            case logginScreen
            case emailScreen
            case passwordScreen
        }
        struct NavigationRoot : View {
            @EnvironmentObject var state: NavigationStack
            @State private var aligment = Alignment.leading
    
            fileprivate func CurrentView() -> some View {
                switch state.list.last {
                case .mainScreenState:
                    return AnyView(GalleryState())
                case .none:
                    return AnyView(LoginScreen().environmentObject(state))
                default:
                    return AnyView(AuthenticationView().environmentObject(state))
                }
            }
            var body: some View {
            GeometryReader { geometry in
                self.CurrentView()
                    .background(Image("background")
                        .animation(.fluidSpring())
                        .edgesIgnoringSafeArea(.all)
                        .frame(width: geometry.size.width, height: geometry.size.height,
                               alignment: self.aligment))
                        .edgesIgnoringSafeArea(.all)
                        .onAppear {
                            withAnimation() {
                                switch self.state.list.last {
                                case .none:
                                        self.aligment = Alignment.leading
                                case .passwordScreen:
                                        self.aligment = Alignment.trailing
                                default:
                                        self.aligment = Alignment.center
                                }
                            }
                        }
                    }
                .background(Color.black)
            }
    
    }
    
    struct ExampleOfAddingNewView: View {
        @EnvironmentObject var state: NavigationStack
        var body: some View {
                VStack {
                    Button(action:{ self.state.push(state: .emailScreen) }){
                    Text("Tap me")
                }
    
            }
        }
    }
    
    
        struct ExampleOfRemovingView: View {
            @EnvironmentObject var state: NavigationStack
            var body: some View {
                VStack {
                    Button(action:{ self.state.pop() }){
                        Text("Tap me")
                    }
                }
            }
        }
    

    In my opinion this bad way, but navigation in SwiftUI much worse

    0 讨论(0)
  • 2020-12-10 19:20

    Possible solutions

    1.if you want to present on top of current view(ex: presentation style in UIKit)

    struct ContentView: View {
        @State var showingDetail = false
    
        var body: some View {
            Button(action: {
                self.showingDetail.toggle()
            }) {
                Text("Show Detail")
            }.sheet(isPresented: $showingDetail) {
                DetailView()
            }
        }
    }
    

    2.if you want to reset current window scene stack(ex:after login show home screen)

    Button(action: goHome) {
        HStack(alignment: .center) {
            Spacer()
            Text("Login").foregroundColor(Color.white).bold()
            Spacer()
        }
    }
    
    func goHome() {
        if let window = UIApplication.shared.windows.first {
            window.rootViewController = UIHostingController(rootView: HomeScreen())
            window.makeKeyAndVisible()
        }
    }
    

    3.push new view (ex: list->detail, navigation controller of UIKit)

    struct ContentView: View {
        var body: some View {
            NavigationView {
                VStack {
                    NavigationLink(destination: DetailView()) {
                        Text("Show Detail View")
                    }.navigationBarTitle("Navigation")
                }
            }
        }
    }
    

    4.update the current view based on @state property, (ex:show error message on login failure)

        struct ContentView: View {
            @State var error = true
            var body: some View {
                ...
                ... //login email
                .. //login password
                if error {
                    Text("Failed to login")
                }
            }
        }
    
    0 讨论(0)
提交回复
热议问题