Isaak
Isaak

Reputation: 1379

SwiftUI Editable NavigationTitle

Is it possible to make the navigation title of SwiftUI editable? Unfortunately the navigationTitle modifier only accepts Text views and not TextField views. I want to do this instead of just using a text field below the navigation bar because I still want the nice default behaviour of having the modified title appear in the navigation bar inline when the user scrolls down and the navigation bar allocates space for the navigation title whether you define one or not.

Upvotes: 5

Views: 2535

Answers (2)

ScottM
ScottM

Reputation: 10502

iOS/iPadOS 16+, macOS 13+

The navigationTitle modifier now accepts a Binding<String> argument, as well as the more usual String-based initializer.

When using a bound value and the navigation bar is in its inline form, the title gains a drop-down menu with a Rename option. Tapping this allows the user to edit the view's title:

struct EditableTitleView: View {
    @State private var title = "View Title"

    var body: some View {
        Text("Editable Title View")
            .navigationTitle($title)
            .navigationBarTitleDisplayMode(.inline)
    }
}

This isn't exactly the same UX as always using a text field, but as it's a standard SwiftUI implementation it's a lot easier to implement.

An iOS 16 implementation of a navigation title with a bound value

For earlier versions of iOS

You can place a custom view in your NavigationView at the position where the title might be expected to go by specifying a ToolbarItem with a placement value of .principal, for example in the code below. I've added the RoundedBorderTextFieldStyle to make the text field more visible:

struct EditableTitleView: View {
  @State private var editableTitle: String = "My Title"
    var body: some View {
      NavigationView {
        Text("View with editable title")
          .toolbar {
            ToolbarItem(placement: .principal) {
              TextField("Title", text: $editableTitle)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            }
          }
      }
    }
}

Screen grab of sample TextField in title bar

Note that if you also add a navigationTitle modifier into your view, its default large style on iOS will still display beneath the toolbar, but if it scrolls off the page it while disappear while your principal item will remain on screen. If you set .navigationBarTitleDisplayMode(.inline) then the larger style title will never display.

I mention this because you should consider keeping a title for your view anyway, for a couple of reasons:

  1. If a NavigationLink pushes a view on the stack, you want a meaningful name to appear in the back button and the list of stacked views that appear on long press.
  2. I haven't checked what happens with VoiceOver when you have a navigation subview without a title. The more you override native behaviour, the more you need to consider whether you are making your app less accessible than the SwiftUI defaults provide.

Upvotes: 7

Helperbug
Helperbug

Reputation: 567

Try a TextField inside of a ToolbarItem in the principal slot of the toolbar. Create a computed property for the destination and give it an editable navigation title, too.

TextField Navigation Title

struct TextFieldNavigationTitleView: View {
    @State var mainTitle = "Main Menu"
    @State var areaOneTitle = "Area One"

    var body: some View {
        NavigationView {
            NavigationLink("App Area One", destination: areaOne)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    TextField("Navigation Title", text: $mainTitle)
                }
            }
        }
    }
    
    var areaOne : some View {
        Text("AREA ONE")
            .toolbar {
                ToolbarItem(placement: .principal) {
                    TextField("Area One Title", text: $areaOneTitle)
                }
            }
    }
}

Upvotes: 2

Related Questions