RW.com: Navigation Tutorial - Part 1
Alright! A new article - technically a tutorial to focus on. This one is all to do with navigation.
Start Time - 14:20
Here is the link, from Audrey Tan:
https://www.raywenderlich.com/5824937-swiftui-tutorial-navigation
Before I start, just having look to see what's there. Good to see the ContentView empty at the moment - that's genuinely good to see we're adding from scratch!
In the 'Artwork' file, we have a custom struct for Artwork, then an array full (17!) of different artwork values. Each has a whole list of properties.
In the MapView file we have some code that I'm not familiar with.
OK, let's go to the actual tutorial!
SwiftUI Basics
Yes I agree with Audrey - I MUCH prefer how the code directly matches to the view, so you can keep track of it all. Also, just the one main ContentView is easier than using storyboards.
Another key point is that UIKit can still be used alongside UI.
Declarative App Development
So what does declarative mean exactly? Apparently it's that you declare what you want your views to look like AND what data they depend on.
SwiftUI deals with changes to the view - updating and recomputing.
Declaring Views
Neat shortcut - option, command and return to get the canvas view on or off
And.... - command, shift and l - gets the library (+ an object) open
Right so to break that down.
You have (left button) - primitive views for layout and control. Stacks, lists, other things like that.
Then (second from left) - modifiers for text, colour, layout, events etc.
A word about modifiers - they are a method that creates a new view from an existing view. Cool.
Creating a Basic List
Here's what we have changed the main bit to look like -
You have the usual start to the struct, of type View...
Then we have inside an array of disciplines.
Then it's the body bit with some View (as usual).
So far in the body we have a primitive view of List, with the code to access the disciplines array. It is iterated through with the local constant of discipline.
*I've renamed that to 'name' here, just for some ownership!
Neat trick - command, option, p - refreshes the view of the canvas (p for preview0
Audrey's main point for the above - MUCH easier than messing around with table view controllers etc.
So this bit of the code is broken down a bit more.
It needs to follow the hashable protocol. The \.self argument is a specific one - it tells List that each item is identified by themselves. All the built in types follow hashable apparently.
Right clicking on the preview play button means you can then select debug preview.
Right I had forgotten about breakpoints. I've added one in.
OK the whole point of that was to show that you need unique items in the id part of the code. I've still got another one there anyway, but it was useful to see the debugging in action!
Navigating to the Detail View
Embedded into a Navigation View -
Creating a Navigation Link
So a NV enables a NL - needs a destination view and label. Like creating a segue without all of the fiddiliness!
This has been created below and separate to ContentView -
Like all structs it has a default initialiser. Then this default init is used inside a text label.
We now have this in the List bit of code -
Start Time - 14:20
Here is the link, from Audrey Tan:
https://www.raywenderlich.com/5824937-swiftui-tutorial-navigation
Before I start, just having look to see what's there. Good to see the ContentView empty at the moment - that's genuinely good to see we're adding from scratch!
In the 'Artwork' file, we have a custom struct for Artwork, then an array full (17!) of different artwork values. Each has a whole list of properties.
In the MapView file we have some code that I'm not familiar with.
OK, let's go to the actual tutorial!
SwiftUI Basics
Yes I agree with Audrey - I MUCH prefer how the code directly matches to the view, so you can keep track of it all. Also, just the one main ContentView is easier than using storyboards.
Another key point is that UIKit can still be used alongside UI.
Declarative App Development
So what does declarative mean exactly? Apparently it's that you declare what you want your views to look like AND what data they depend on.
SwiftUI deals with changes to the view - updating and recomputing.
Declaring Views
Neat shortcut - option, command and return to get the canvas view on or off
And.... - command, shift and l - gets the library (+ an object) open
Right so to break that down.
You have (left button) - primitive views for layout and control. Stacks, lists, other things like that.
Then (second from left) - modifiers for text, colour, layout, events etc.
A word about modifiers - they are a method that creates a new view from an existing view. Cool.
Creating a Basic List
Here's what we have changed the main bit to look like -
struct ContentView: View {
let disciplines = ["statue", "mural", "plaque"]
var body: some View {
List(disciplines, id: \.self) { discipline in
Text(discipline)
}
}
}
You have the usual start to the struct, of type View...
Then we have inside an array of disciplines.
Then it's the body bit with some View (as usual).
So far in the body we have a primitive view of List, with the code to access the disciplines array. It is iterated through with the local constant of discipline.
*I've renamed that to 'name' here, just for some ownership!
Neat trick - command, option, p - refreshes the view of the canvas (p for preview0
Audrey's main point for the above - MUCH easier than messing around with table view controllers etc.
So this bit of the code is broken down a bit more.
List(disciplines, id: \.self) { name in
Text(name)
It needs to follow the hashable protocol. The \.self argument is a specific one - it tells List that each item is identified by themselves. All the built in types follow hashable apparently.
Right clicking on the preview play button means you can then select debug preview.
Right I had forgotten about breakpoints. I've added one in.
OK the whole point of that was to show that you need unique items in the id part of the code. I've still got another one there anyway, but it was useful to see the debugging in action!
Navigating to the Detail View
Embedded into a Navigation View -
NavigationView {
List(disciplines, id: \.self) { name in
Text(name)
}
.navigationBarTitle("Disciplines")
}
Creating a Navigation Link
So a NV enables a NL - needs a destination view and label. Like creating a segue without all of the fiddiliness!
This has been created below and separate to ContentView -
struct DetailView: View {
let discipline: String
var body: some View {
Text(discipline)
}
}
Like all structs it has a default initialiser. Then this default init is used inside a text label.
We now have this in the List bit of code -
List(disciplines, id: \.self) { discipline in
NavigationLink(
destination: DetailView(discipline: discipline)) {
Text(discipline)
}
Now we have an arrow at each row! So this is the navigation link. Makes sense so far.
Right, we have then added to the DetailView struct, and that's where the NB title has gone when each item has been clicked on!
So far, I appreciate how Audrey has explained each bit of code and made it logical. Nothing too complex that I can't make sense of.
This is called a Master-Detail app. You have the main screen, then a new screen for each item from the master. Cool!
Revisiting Honolulu Public Artworks
A strange title (it's where the public artworks are)! So we're in the Artwork struct now. Eight properties - all constants except the last one which is editable (reaction).
OK a key thing that came up when changing the code so that the ArtData stuff was accessible, because it was a custom type it was not hashable! So .self was changed to .title. A few other changes too.
struct ContentView: View {
let artworks = artData
var body: some View {
NavigationView {
List(artworks, id: \.title) { artwork in
NavigationLink(
destination: DetailView(artwork: artwork)) {
Text(artwork.title)
}
}
.navigationBarTitle("Artworks")
}
}
}
struct DetailView: View {
let artwork: Artwork
var body: some View {
Text(artwork.title)
.navigationBarTitle(Text(artwork.title), displayMode: .inline)
}
}
Creating Unique id Values (UUID)
Right. At the moment, it's bringing up all of the names of the artists, with each one repeated - each statue being the same name repeated and so on for plaque and mural! This is where we need a UUID - so each object is unique and NOT repeated....
So the solution is smart. The id needs to be a property in the ArtData struct. Then is used in the NV bit in the CV.
I just smashed something else! I realised I needed the image in each of the DetailView, so changed Text to Image and .text to .imageName. Boom!
Conforming to Identifiable
Last bit for now!
Even better than the UUID bit...
Extending the artwork struct so that it is identifiable...
extension Artwork: Identifiable { }
This means that NO id bit is needed and the code inside the NV is now even easier!
Now we STILL need the UUID bit in the struct - that was not a waste of time.
And that's a good time to stop! Over an hour spent on GOOD stuff! All interesting and useful. And easily try-outable, which I struggled with the previous two articles.
Finish Time -15:39 (approx 1 hour 15)
A summary of points before I am done:
- Declarative - means what you want your views to look like and what data is then needed
- Some good shortcuts for the library and canvas
- Modifiers are technically methods (even though they're kinda like properties with the dot syntax)
- No other storyboards/viewcontroller objects needed in SwiftUI
- Navigation View and Navigation Link - great ways of having the option of going to other screens
- Having another view (DetailView) is for the next screen - where each list item takes you to
- Hashable - is the case in native types but not custom ones, unless specified
- Master-Detail app is having a main Content View, then the Detail View linked in.
- UUID - ensures that there aren't objects repeated. Needs to be in the custom struct/class as a property, and identifiable needs to be the protocol to conform to
Loads of stuff! Looking forward to more tomorrow.
Comments
Post a Comment