Not quite grokking declarative syntax

I'm having trouble wrapping my head around SwiftUI's declarative syntax. For instance, in the Landmarks code, when creating the List ...


var body: some View {

NavigationView {

List(landmarkData) { landmark in NavigationButton(destination:LandmarkDetail()) {

LandmarkRow(landmark: landmark)

}

}.navigationBarTitle(Text("Landmarks"))

}

}


... why is the navigationBarTitle associated with the List? I *think* it's analagous to UINavigationControllers, where each UITableViewController has a navigationItem (and a title). Is that right?


More confusingly (for me), why is the LandmarkRow inside the NavigationButton? I think of a button as part of a UITableViewCell, so here the analogy breaks down. Can someone explain this?

Replies

navigationBarTitle is associated with the list, as it assigns a title value to the list, which is displayed IF it is embedded in a NavigationView.

As far as the row being embedded in a button, you are assigning the row the functionality of a button (I'd think it's analogous to displaying the row 'within' a button).


However, documentation is sparse, so, I could be desperately wrong on these.

I think you're basically correct. Any View can be modified by .navigationBarTitle, although I also wonder if there's a reason NOT to do it at the top level (on the NavigationView itself).


On the matter of rows inside buttons, this was briefly touched on in one of the WWDC videos IIRC. With the row inside the button, you can simply tap the row on iOS to trigger the button action. With the button inside the row, tapping the row doesn't trigger the action, unless you actually tap the button within the row.

Wrapping a View in a NavigationView is roughly the same as wrapping a UIViewController in an UINavigationController.


Now a pop quiz. What happens if you push another UIViewController in its own UINavigationController? You don't, right? You may present one, but if you already have a UINavigationController you simply push a VC onto the navigation stack.


A NavigationView creates a navigation stack, with a view inside the stack. A NavigationButton pushes a new View onto the existing stack. That means like the above example, the new "detail" view is NOT contained in a NavigationView.


Which brings us down to navigationBarTitle, which is simply a modifier on a view used to "set" the current NvaigationView's title, be it ours or a parents.


As to the NavigationButton, it's simply a way of making ANY content (a list row, some text, an image) into a button that has the ability to push new views onto the stack.


A list row without a nav button is just a row of data. A row WITH a nav button is tappable, adds a disclosure indicator, and will expose a detail view.


Being able to wrap ANY piece of content (even complex content) and make it into a button is a pretty powerful concept.

This might help with the navigationBarTitle modifer question....



https://medium.com/@michaellong/swiftui-deep-inside-navigationview-4d25d57a236c?source=friends_link&sk=573fb99e9de4a55578e5b0f288cd82b5

It's also worth noting (I ran into this today) that drawing a row inside a button on MacOS provides the expected behavior, 'unless' you tap on empty space (for example, if you have a Spacer() in your row). It seems that even inside a button, you must tap/click a 'substantive' control in the row.

That article was extremely useful - it cleared up a few head-scratchers! Thanks for pointing it out.