0

I have a SwiftUI app which uses a custom navigation bar. Because of that, I need to handle the back navigation separately (both the back button and the swipe gesture). Everything went fine up until now, when I need to use a TabView to swipe between pages. The code below illustrates what I'm trying to achieve:

ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: SecondView()) {
                Text("Go to second view")
            }
        }
    }
}

SecondView.swift

import SwiftUI

// Being able to go back by swiping
// https://stackoverflow.com/questions/59921239/hide-navigation-bar-without-losing-swipe-back-gesture-in-swiftui
extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }
    
    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}

struct SecondView: View {
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        VStack(alignment: .leading) {
            Image(systemName: "chevron.left")
                .foregroundColor(Color(.systemBlue))
                .font(.title2)
                .onTapGesture {
                    self.presentationMode.wrappedValue.dismiss()
                }
                .padding()
            TabView {
                Text("Test 1")
                    .tag(1)
                Text("Test 2")
                    .tag(1)
                Text("Test 3")
                    .tag(3)
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
        }
        .background(Color(.systemGray6))
        .navigationBarHidden(true)
    }
}

Note that I didn't add the custom navigation bar for the second view, I've just hidden the default navigation bar, as the custom bar is not needed to solve this problem.

When the user is inside the SecondView and presses the back button, everything works as expected. The problem appears when he tries to swipe back, as the swipe back gesture is captured by the TabView. I want to keep the 'swipe-between-pages' functionality of the TabView while being able to go back to ContentView when the user swipes right from the leftmost part of the screen.

This problem only appears when using TabViews, other types of content handle the swipe back gesture without problems.

To solve this problem, I could add a horizontal padding to the TabView like this:

TabView {
    // content
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.padding(.horizontal)

and then the user would have some space to swipe back, but this solution is not so good when some views inside the TabView need to take the whole width of the screen.

Is there any way to handle the swipe back gesture in this particular case? Maybe another possible solution would be customizing the TabView to ignore the drag gesture when the first view is presented and a swipe right gesture is captured (I don't know how to implement that).

Liviu
  • 142
  • 4
  • 11
  • I'd say that solution with `UINavigationController` extension is pretty bad, check out [this answer](https://stackoverflow.com/a/38274660/3585796) why you shouldn't override methods in extensions. – Phil Dukhov Sep 16 '21 at 13:41
  • Thanks, @PhilipDukhov. I read the answer, but I don't know of any better solution for achieving that. If you know any other possible solution I'll be glad to try it. Also, do you know how I could solve the TabView problem? – Liviu Sep 16 '21 at 14:12

1 Answers1

1

I ran into this same problem. I solved it by wrapping my first tabview in with a geometryReader. When the bounds of that view is more than a quarter off the screen, I dismiss the view.

Matt
  • 11
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 30 '21 at 11:32