iosswiftswiftuiuipageviewcontrolleruiviewrepresentable

Swipe between two pages with Segmented-style Picker in SwiftUI


I have a Picker with .pickerStyle(SegmentedPickerStyle()) to make it a segmented control. I want to make the pages smoothly swipe between, rather than replacing the view using a conditional statement.

Here is a gif of what I have made so far:

What I have made

Here is the code so far (controlled by an if, instead of switching between different pages):

struct AuthView: View {

    @State private var authPath = 0

    /* ... */

    var body: some View {
        VStack {
            Picker(selection: $authPath, label: Text("Authentication Path")) {
                Text("Log In").tag(0)
                Text("Sign Up").tag(1)
            }
            .pickerStyle(SegmentedPickerStyle())

            Spacer()

            if authPath == 0 {
                LogInView(/* ... */)
            } else {
                SignUpView(/* ... */)
            }

            Spacer()
        }
        .padding()
        .background(Color("Color.Background").edgesIgnoringSafeArea(.all))
    }
}

I want something similar to UIPageViewController. If there is a SwiftUI version or a good alternative, that would really help.

However, if I do need to resort to UIKit with UIViewRepresentable, I don't know how I would implement it with SwiftUI.


Solution

  • These other answers pointed me in the right direction, but the code seems a bit verbose or didn't function as intended.

    Here is what changed to get mine working:

    Original:

    struct AuthView: View {
    
        @State private var authPath = 0
    
        /* ... */
    
        var body: some View {
            VStack {
                Picker(selection: $authPath, label: Text("Authentication Path")) {
                    Text("Log In").tag(0)
                    Text("Sign Up").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
    
                Spacer()
    
                if authPath == 0 {
                    LogInView(/* ... */)
                } else {
                    SignUpView(/* ... */)
                }
    
                Spacer()
            }
            .padding()
            .background(Color("Color.Background").edgesIgnoringSafeArea(.all))
        }
    }
    

    New:

    struct AuthView: View {
    
        @State private var authPath = 0
    
        /* ... */
    
        var body: some View {
            VStack {
                Picker(selection: $authPath, label: Text("Authentication Path")) {
                    Text("Log In").tag(0)
                    Text("Sign Up").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
                .padding()
    
                Spacer()
    
                if authPath == 0 {
                    LogInView(/* ... */)
                        .animation(.default)
                        .transition(.move(edge: .leading))
                        .padding()
                }
                if authPath == 1 {
                    SignUpView(/* ... */)
                        .animation(.default)
                        .transition(.move(edge: .trailing))
                        .padding()
                }
    
                Spacer()
            }
            .background(Color("Color.Background").edgesIgnoringSafeArea(.all))
        }
    }