Collapse button NavigationView SideBar SwiftUI

Hello

How can I remove the Collapse button that is on the navigationBar in iPadOS?

Thank You!

Accepted Reply

If you do want SwiftUI only solution, you should not have included the tag UIKit.

When the tags or the terms may not be appropriate enough, you should better try to explain your issue more precisely. Including codes and/or images will help avoiding confusion of readers.


What I want to really achieve is the sidebar that is used in the iPad Settings app

I could not find a simple way to hide Collapse button on navigation bar.

Also, as far as I checked the UI design of Settings app of iOS 14 & 15

  • The UI does not change whether in portrait or in landscape
  • Each row in the list does not have a disclosure indicator ()

So, I guess, the Settings app is not constructed simply using the ColumnNavigationViewStyle and NavigationLink.

You may need to do it all by yourself.

A little bit simplified example:

struct ContentView: View {
    @State var secondViewTitle: String?
    let rows = ["Hello", "World"]
    var body: some View {
        HStack {
            NavigationView {
                List {
                    Section {
                        ForEach(rows, id: \.self) { row in
                            Button(action: {
                                if self.secondViewTitle == row {
                                    self.secondViewTitle = nil
                                } else {
                                    self.secondViewTitle = row
                                }
                            }, label: {
                                HStack {
                                    Text(row)
                                        .padding()
                                    Spacer()
                                }
                            })
                            .background(self.secondViewTitle == row ? Color.accentColor : Color.white)
                            .listRowInsets(EdgeInsets())
                        }
                        .foregroundColor(Color.primary)
                    }
                }
                .listStyle(InsetGroupedListStyle())
                .navigationTitle("Test")
            }
            .navigationViewStyle(StackNavigationViewStyle())
            .frame(width: 360)
            SecondView(title: secondViewTitle)
            .frame(maxWidth: .infinity)
        }
    }
}

struct SecondView: View {
    let title: String?
    var body: some View {
        Text("\(title ?? "")")
    }
}

Replies

I tested the SO solution and it works (here UIKit):

class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate {

    let isaPad = (UIDevice.current.userInterfaceIdiom == .pad) 

    override func viewDidLoad() {
        
        super.viewDidLoad()

        // Do any additional setup after loading the view.
         self.preferredDisplayMode = UISplitViewController.DisplayMode.oneBesideSecondary
        self.maximumPrimaryColumnWidth = 200
        self.delegate = self
    }
    
    func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewController.DisplayMode) {

      if isaPad {
        svc.presentsWithGesture = displayMode != .oneBesideSecondary
      }
    }

}
  • How would I do it for SwiftUI? Thank You

  • Show the code you have for splitViewController (even this does not directly exist in SwiftUI). It may be enough to simply set       svc.presentsWithGesture = false       But show the code to find where to put it.

  • Does your actual code show the collapse button ? Please show this code in SwiftUI.   Or at least show a screen capture with the collapse button.   Note:    This may be useful as well.      https://stackoverflow.com/questions/63552716/how-to-run-the-split-view-on-ipad-using-swiftui

Add a Comment

Does your actual code show the collapse button ?

Yes

Here is a very similar code

struct ContentView: View {
    var body: some View {
        NavigationView{
            List{
                NavigationLink {
                    Text("Hello")
                } label: {
                    Text("Hello")
                }
                
                NavigationLink {
                    Text("World")
                } label: {
                    Text("World")
                }
            }
            .navigationTitle("Test")
        }
    }
}

What I want to really achieve is the sidebar that is used in the iPad Settings app, if you know how to do that, it would be perfect. Thank You very much

If you do want SwiftUI only solution, you should not have included the tag UIKit.

When the tags or the terms may not be appropriate enough, you should better try to explain your issue more precisely. Including codes and/or images will help avoiding confusion of readers.


What I want to really achieve is the sidebar that is used in the iPad Settings app

I could not find a simple way to hide Collapse button on navigation bar.

Also, as far as I checked the UI design of Settings app of iOS 14 & 15

  • The UI does not change whether in portrait or in landscape
  • Each row in the list does not have a disclosure indicator ()

So, I guess, the Settings app is not constructed simply using the ColumnNavigationViewStyle and NavigationLink.

You may need to do it all by yourself.

A little bit simplified example:

struct ContentView: View {
    @State var secondViewTitle: String?
    let rows = ["Hello", "World"]
    var body: some View {
        HStack {
            NavigationView {
                List {
                    Section {
                        ForEach(rows, id: \.self) { row in
                            Button(action: {
                                if self.secondViewTitle == row {
                                    self.secondViewTitle = nil
                                } else {
                                    self.secondViewTitle = row
                                }
                            }, label: {
                                HStack {
                                    Text(row)
                                        .padding()
                                    Spacer()
                                }
                            })
                            .background(self.secondViewTitle == row ? Color.accentColor : Color.white)
                            .listRowInsets(EdgeInsets())
                        }
                        .foregroundColor(Color.primary)
                    }
                }
                .listStyle(InsetGroupedListStyle())
                .navigationTitle("Test")
            }
            .navigationViewStyle(StackNavigationViewStyle())
            .frame(width: 360)
            SecondView(title: secondViewTitle)
            .frame(maxWidth: .infinity)
        }
    }
}

struct SecondView: View {
    let title: String?
    var body: some View {
        Text("\(title ?? "")")
    }
}

func setDisplayModeButtonVisibilityHidden() {
    typealias BlockType = @convention(c) (Any, Selector, UISplitViewController.Style) -> Any

    let selector: Selector = #selector(UISplitViewController.init(style:))
    let method: Method = class_getInstanceMethod(NSClassFromString("SwiftUI.NotifyingMulticolumnSplitViewController"), selector)!
    let originalImp: IMP = method_getImplementation(method)
    let original: BlockType = unsafeBitCast(originalImp, to: BlockType.self)

    let new: @convention(block) (Any, UISplitViewController.Style) -> Any = { (me, arg0) -> Any in
        let object: UISplitViewController = original(me, selector, arg0) as! UISplitViewController
        object.displayModeButtonVisibility = .never
        return object
    }

    let newImp: IMP = imp_implementationWithBlock(new)
    method_setImplementation(method, newImp)
}

... on your @main App,

@main
struct YourApp: App {
    init() {
        setDisplayModeButtonVisibilityHidden()
    }

    / ** /
}
Post not yet marked as solved Up vote reply of pook Down vote reply of pook
  • This is a real solution! Thanks!!!

Add a Comment