0

I have a segmented control with two segments as shown in the image see image here. I want to enable the user to switch between the two segments by swiping right or left, and display the corresponding views accordingly. I have looked through several articles, but I have not found a solution to implement this functionality.

I used buttons to implement this feature, but I'm unsure how to enable swipe functionality.

  1. How to implement a left or right DragGesture() that trigger a switch case in SwiftUI?
  2. How to detect Swiping UP, DOWN, LEFT and RIGHT with SwiftUI on a View
struct ScheduleView: View {
    // MARK: - Variables
    @State private var playerName: String = ""
    @State private var pastShown: Bool = false
    @State private var presentAlert: Bool = false
    @State private var goToGroupChat: Bool = false
    private var items = ["Upcoming", "Past"]
    
    var body: some View {
        NavigationView {
            ZStack {
                VStack {
                    HStack {
                        VStack(alignment: .leading) {
                            Text("Hello!,")
                                .robotoRegularFont(size: 14)
                                .foregroundColor(Color.custom64B054Color)
                            Text("John Andrew")
                                .robotoRegularFont(size: 14)
                                .foregroundColor(Color.custom333333Color)
                        }
                        Spacer()
                        Image("appIcon_icon")
                            .resizable()
                            .frame(width: 32, height: 32)
                    }
                    .padding(.top, 24)
                    
                    // MARK: - Upcoming and Past Views
                    VStack(spacing: 8) {
                        HStack(alignment: .center, spacing: 0) {
                            Spacer()
                            
                            // MARK: - Button Upcoming
                            ZStack {
                                Button {
                                    print("Upcoming action")
                                    self.pastShown = false
                                } label: {
                                    Text("Upcoming")
                                        .font(.custom(self.pastShown ? "Roboto-Light" : "Roboto-Medium", size: 15))
                                        .foregroundColor(self.pastShown ? .black.opacity(0.7) : .black)
                                }
                            }
                            .frame(width: UIScreen.main.bounds.width / 2 - 18)
                            Spacer()
                            Spacer()
                            
                            // MARK: - Button Past
                            ZStack {
                                Button {
                                    print("Past action")
                                    self.pastShown = true
                                } label: {
                                    Text("Past")
                                        .font(.custom(self.pastShown ? "Roboto-Medium" : "Roboto-Light", size: 15))
                                        .foregroundColor(self.pastShown ? .black : .black.opacity(0.7))
                                }
                            }
                            .frame(width: UIScreen.main.bounds.width / 2 - 18)
                            Spacer()
                        }
                        
                        let upcoming = Capsule()
                            .fill(Color.black.opacity(self.pastShown ? 0.2 : 1))
                            .frame(maxWidth: .infinity, maxHeight: 1.5)
                        let past = Capsule()
                            .fill(Color.black.opacity(self.pastShown ? 1 : 0.2))
                            .frame(maxWidth: .infinity, maxHeight: 1.5)
                        
                        HStack(alignment: .center, spacing: 0) {
                            upcoming
                            past
                        }
                    }
                    .padding(.top, 8)
                    .padding(.horizontal, -18)
                    
                    ScrollView(.vertical, showsIndicators: false) {
                        // MARK: - Past View
                        if self.pastShown {
                            Text("past")
                        } else {
                            // MARK: - Upcoming View
                            LazyVStack(spacing: 20) {
                                MatchInfoCell(playerType: "Doubles", skillRange: "minimum", noOfParticipants: "2/4", date: "Tues, Oct 25", time: "04:00 PM", court: "Tour Greens Houston Serves The Houston Area", isForSchedule: true, lookingButtonAction: {
                                    print("lookingButtonAction")
                                }, gameOnButtonAction: {
                                    print("gameOnButtonAction")
                                }, noGameButtonAction: {
                                    print("noGameButtonAction")
                                }, messageButtonAction: {
                                    print("messageButtonAction")
                                    self.goToGroupChat.toggle()
                                }, addGuestButtonAction: {
                                    print("addGuestButtonAction")
                                    withAnimation {
                                        self.presentAlert.toggle()
                                    }
                                })
                            }
                        }
                    }
                    .padding(.top)
                    .background(Color.clear)
                }
                .padding(.horizontal, 18)
                
                // MARK: - Custom Alert for Add Guest
                if self.presentAlert {
                    VStack {
                        CustomAlertView(alertTitle: "Are you sure you want to add a Guest in this match?", nonFilledButtonTitle: "No", filledButtonTitle: "Yes", nonFilledButtonAction: {
                            withAnimation {
                                self.presentAlert.toggle()
                            }
                        }, filledButtonAction: {
                            withAnimation {
                                self.presentAlert.toggle()
                            }
                        }, presentAlert: $presentAlert)
                    }
                }
                
                // MARK: - Navigate to Group Chat
                NavigationLink("", destination: GroupChatView().navigationBarHidden(true).navigationBarBackButtonHidden(true), isActive: $goToGroupChat)
            }
            .navigationBarHidden(true)
            .navigationBarBackButtonHidden(true)
        }
    }
}

If someone could provide me with guidance on how to achieve this, I would greatly appreciate it!

Thank You!

1

1 Answer 1

0

So, to make it work I used almost of all of your code. The important part is the gesture modifier:

.gesture(
            DragGesture()
                .onChanged({ value in
                    let translationX = value.translation.width
                    let velocity = abs(value.velocity.width)
                    let predictedEnd = value.predictedEndTranslation.width
                    print("Entered \(translationX), velocity \(velocity)")
                    if (translationX > 200 || predictedEnd > 200) && velocity > 500 {
                        withAnimation(.smooth) {
                            self.pastShown = false
                        }
                    } else if (translationX < -200 || predictedEnd > -200) && velocity > 500 {
                        withAnimation(.smooth) {
                            self.pastShown = true
                        }
                    }
                })
        )

Play around and tune those values as you need. You can add it at the end of your ZStack which embeds your two views (Upcoming and past). Also, you need to add this line to your ScrollView enclosing the "past" tab:

.frame(maxWidth: .infinity, maxHeight: .infinity)

Making it look like this:

ScrollView(.vertical, showsIndicators: false) {
                    // MARK: - Past View
                    if self.pastShown {
                        Text("past")
                    } else {
                        // MARK: - Upcoming View
                        LazyVStack(spacing: 20) {
                           // Your code here
                        }
                    }
                }
                .padding(.top)
                .background(Color.clear)
                .frame(maxWidth: .infinity, maxHeight: .infinity) // <-- The new line

Otherwise the drag gesture would only be detected on a really narrow strip of the screen making it impossible for the swipe to work properly. Let me know if it works for youenter image description here

Note: I used a red background to let you better see the swipeable area.

Sign up to request clarification or add additional context in comments.

7 Comments

Hello @MatBuompy Thank you for your efforts! I'm getting these errors: 1) Value of type 'DragGesture.Value' has no member 'velocity' 2) Type 'Animation?' has no member 'smooth'
Maybe you are using an older version of SwiftUI. You can get rid of the .smooth animation and choose another one. The same goes for velocity.
Unfortunately No! I have been trying but no result!
I have removed .smooth animation and calculated velocity like this: let velocity = CGSize( width: value.predictedEndLocation.x - value.location.x, height: value.predictedEndLocation.y - value.location.y ) from this link: stackoverflow.com/a/65835678/22171290
My solution works on ios 17 (maybe even 16). I could not know which version you are using. I would appreciate if you could mark my answer as correct or at least upvote it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.