Search code examples
swiftuipopoverswiftui-navigationview

SwiftUI popover from navigationView toolbar


I want to create a custom speech bubble like menu in my navigation toolbar, which I’m going to use to toggle between different view options.

The design I’m looking for is pretty much exactly what Apple has done in the Reminders app, tapping the share button: 1 I don’t have any functional code yet because everything I tried has failed and I haven’t found anything online on how to customize overflows like this. I’m assuming it should go something like this:

NavigationView {
    // Content views
    .navigationTitle("Title")
    .toolbar {
        ToolbarItem(placement: .topBarTrailing) {
            Menu {
               // Probably the code I’m looking for but failed to accomplish
            } label: {
                Label("Text", systemImage: "ellipsis")
            }
        }
    }
}

Apple generally has a few different designs for these menus in various apps. How to get more control of how these menus look?


Solution

  • After some research and experiments with tooltips and popovers I came up with this:

    @State var viewOptionsIsShown = false
    @State var selectedView: String = "list"
    
    NavigationView {
          // Content
    
          .navigationTitle("Title")
          .navigationBarTitleDisplayMode(.inline)
          .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                      Button {
                            viewOptionsIsShown.toggle()
                      } label: {
                            Label("Label", systemImage: "slider.horizontal.3")
                      }
                      .popover(isPresented: $viewOptionsIsShown, attachmentAnchor: .point(.bottom), arrowEdge: .bottom, content: {
                              PopoverOptions(selectedView: $selectedView)
                             .presentationCompactAdaptation(.popover)
                      })
                // Additional ToolbarItems
           }
    }
    

    The toolbarItem button toggles the viewOptionsIsShown Bool. The key and the answer to the question is the .popover modifier attached to the button. It is binded to the same Bool, with some display parameters. And for the content, a separate view struct is called, PopoverOptions with a binding to selectedView. That separate view can be designed however you like, in my case with three buttons that you can toggle between which returns three different state values for selectedView.

    Note the .presentationCompactAdaption modifier. By default, smaller screen sizes (iPhone) will show a sheet rather than a popover. This overrides to always show a popover.

    Final result 1