Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - disable NavigationView back button menu

So, I have the following code:

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink("Page", destination: PageView())
                .font(Font.system(.largeTitle))
        }
    }
}

struct PageView: View {
    var body: some View {
        Text("Hello, world!")
    }
}

When the "Page" NavigationLink is selected, you are redirected to a new screen (PageView). When you long-press (hold) the back button to go back to the main screen (ContentView), a menu appears (new feature in iOS14+):

enter image description here

Is there a way to disable the menu popup on a long-press gesture, using SwiftUI (without adding custom back button)?

Cheers everyone, thanks for your time!

like image 864
Tropicano Avatar asked Sep 05 '26 20:09

Tropicano


2 Answers

I was able to find a workaround. Not pretty, but it works ^^.

First I was trying to use Introspect library to change the underlying UIKit components since there is a Solution to your problem for UIKit. But it didn't turn out well.

So here comes the workaround.

Idea

Overlay the back button with an invisible view that has the same tap gesture, but no long press for the menu.

Solution

Finding out and reaching the exact position of the back button independent of user device type.

Code:

struct ContentView: View {
    
    @State private var showPageView = false
    
    var body: some View {
        NavigationView {
            NavigationLink("Page", destination: PageView(), isActive: $showPageView)
                .font(Font.system(.largeTitle))
        }
        .overlay(NavigationBackButtonHiddenTouchView(isActive: $showPageView))
    }
}

struct PageView: View {
    
    var body: some View {
        ZStack {
            Text("Hello, world!")
        }
    }
}

struct NavigationBackButtonHiddenTouchView: View {
    
    @Binding var isActive: Bool
    
    var body: some View {
        VStack {
            HStack {
                Color.black.opacity(0.0000001).frame(width: 80, height: 35)
                    .onTapGesture { isActive = false }
                
                Spacer()
            }
            .frame(height: navBarHeight)
            
            Spacer()
        }
    }
    
    var navBarHeight: CGFloat = {
        return UINavigationController().navigationBar.frame.size.height
    }()
}

Problem

Making it reusable for further navigation links (you need to handle it manually, ugly but possible)

You might also have to handle hiding NavigationBackButtonHiddenTouchView from your parent view, if it causes complications.

like image 154
Mofawaw Avatar answered Sep 07 '26 11:09

Mofawaw


Yes! That's a solution. Nice job. The only problem is, that you don't have a click indication on the button. I have cleaned the code a bit:

struct BackButtonMenuDisabled: ViewModifier {
private enum Constants {
    static let overlayOpacity = 0.01
    static let backButtonWidth: CGFloat = 50
}

@Binding private var isActive: Bool

init(isActive: Binding<Bool>) {
    self._isActive = isActive
}

private var navigationBarHeight: CGFloat {
    UINavigationController().navigationBar.frame.size.height
}

func body(content: Content) -> some View {
    content.overlay(
        VStack {
            HStack {
                Color.black.opacity(Constants.overlayOpacity)
                    .frame(width: Constants.backButtonWidth, height: navigationBarHeight)
                    .onTapGesture {
                        isActive = false
                    }
                Spacer()
            }
            Spacer()
        }
    )
}
like image 24
Tropicano Avatar answered Sep 07 '26 10:09

Tropicano



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!