Hey, everyone, my name is Nick Manning. And I'm a flutter engineer. So I create flutter
apps in my free time. And I kind of also create tutorial videos about it. So I am the creator
of flutter Crash Course calm. Thanks very much to free code camp.org for sponsoring this video. And
let's get started. Hey, everyone, my name is Nick Manning. And this is my flutter Crash Course. So
I'm really excited to offer this to you because I've taken about six or eight months of filming
and content creation. And I've boiled it down into this course. And what it's meant to do is save you
time learning flutter. So what you see here is my show notes. And as every video I'm going to do,
I'm going to walk through my show notes, so you can read along and take notes on your own. And in
terms of my background, I've been writing software for about 20 years, five of those as an iOS
engineer. So to follow along, some of you might not want to follow along, you just want to watch,
that's fine. But you're going to need everything that the flutter website said, so any kind of
main operating system, popular operating system, latest version of flutter, and an iOS simulator or
Android emulator, so make sure you have that installed and all set up. So if you want to,
if you don't know how to set that up, you're having problems, you can go to my website or the
YouTube channel that I have. And I have specific videos on how to set up flutter, step by step for
Windows and OSX. So experience level required. So you need to have experience with one existing
programming language. And also you something that you've coded like a website or a web app, or even
a mobile app, you don't need to but something that you've done in the past. So that you know some
basic programming, you have some basic programming skills. So let's get started here. Um, if you want
to, again, go see other videos, check out flutter Crash Course calm, but we're gonna now start our
first lesson, which is chapter one, which is creating a basic screen. So stay tuned. Hey,
everyone. So in this lesson, we're going to cover layout in flutter. So we're going to be using a
widget called column. And what column does its lets us layout widgets from top to bottom. So let
me show you what we're going to be eventually coding. This is the location detail screen of
our app. It's called the tourism co app. And the location Details screen shows a number of things.
And you can tell that we can use this column widget because things are widgets here are laid
out from top to bottom. So there's another widget called a row and row lets you lay out stuff from
left to right, for example. So but you're pretty much most of the time going to use this column
widget because a lot of content on a mobile app is all is is a column style, layout. So in this
video, we're going to cover implementing three text sections. So text sections, let us define
the area for let's say, let's say we want to show summary and then this snippet of text, that's what
a text section will be. So let's get coding on. So last time we have this, we left off with this home
page. And we're going to rename it to location detail. So let's do that really quick. and name
this directory location detail because that's the convention of the code order organization we're
going to use. So we have a number of screens, and each directory is the name of the screen,
and then the name of the file, the main file that defines that screen is also that name.
So let's define that. And I'm going to now stop my app and restarted I can't use the hot reload
because I am changing the file name. So sometimes we can't use hot reload. So while that's starting,
let's go over column. So I'm gonna render three tech sections. But now I'm not going to just
display text, I'm going to display colored boxes. So colored boxes are going to show us how that
content is that the bounding areas for each piece of content. So one way we can define a colored box
is using a widget in flutter called container. So container is kind of like the div of flutter.
It's a div in HTML is just a bounding area that's flexible, you have different parameters you can
define. One of those parameters is color. So I can just say container and define some color I can use
a property called decoration so There's different types of decorations. One is a box decoration,
that's just a generic way to define a box, some sort, and I can style that box using the color
parameter. So I'm going to say color. And I'm gonna say colors dot red. So this in Dart means
colors that red, red is a static member, meaning you don't need to instantiate the colors class to
refer to it. So that's why you have class name, dot and then the value here. So lastly, container
will take a child. So we're gonna say child text, and then whatever. And then we're gonna save it.
And one thing we didn't do is define our column forgot to do that. So column has a parameter
called children and children is an a, it's a list, it's not a single widget. So and it is a list
because you can have multiple items in your list. So we're going to find three containers here. So
I'm going to just copy and paste this, and one's going to be read, one's going to have background
of green, and we're going to is going to have a background on blue. Now, nothing's happening
here. Because we want to define some parameters here, I can define some texts, that's fine, I'll
just do that real quick. But, you know, look at the screen, I mean, nothing really is happening.
That's interesting. It's just the finding these little tiny boxes here, you can't even see the
text. So what I want to do is define something called main axis alignment. And what main axis
alignment does is, it lets us control how each child is vertically spaced on the screen or
how it's laid out. And when I say vertically, for column, it's vertically. So main axis is something
generic. So I'll take a step back. So main axis is the main axis of the widget that you're using. So
if you're using a column, the main axis will be a vertical line on the screen from top to bottom. If
you're using the row widget, the main axis will be a horizontal line from left to right. So the main
axis says something that's loosely defined, and it depends on the widget that you're using. So So the
main axis alignment controls how content is laid out on from top to bottom, I have the following
options, I have space evenly. So let's try that. I'll just go ahead. And you'll see that the each
box is spaced evenly on the screen. Pretty simple. I can also say let's say end. So if I say end,
each item will be rendered from the very bottom of my column, and column occupies the entire screen.
There's other options I don't need to cover right now. But the most common one is start. So we're
going to stick to that. The second parameter for column or row, we're not going to cover row in
this video, but it's also a parameter for row is cross axis alignment. And cross axis alignment is
the exact opposite of the main axis. It's the kind of the kind of virtual horizontal line on
the screen. So if the main axis goes from top to bottom, the cross axis goes from left to right on
the screen. And let me show you what options you have here. So I have cross axis axis alignment,
baseline center and start stretch. So we're not going to cover all of these, but one of
the most common ones is stretch. So it's making sure that each item of my column is stretched
from left to right. So let's save that. And I'll show you now each item is stretched from left to
right. And cool. Um, that's it. So this code looks pretty ugly. But at least we have some containers
where we can store text. So once we do continue on implementing this screen will have a nice bounding
area. And content will flow nicely from top to bottom. And it'll also be stretched. So let's
clean up the code. That's the last step of this video. And since these are reusable kind of pieces
of code here, we're going to make this into a widget. So I'm going to take the template of
this file, like all the import the class here, the build method, and I'm going to copy it, and I'm
going to create a new file called text section. So the reason why we're defining the file here
in the location detail screen is because we're not going to reuse this widget. We're going to
define it anywhere else in the app so we can keep it local to this screen, it's going to paste this
in. And we have a nice template for our stateless widget we're going to build, which is defining a
text section, I'm going to name it like that. And then in the location Details screen, I can copy or
cut the content we want to show. And I'm going to say container. And I'm going to say returned
here. And now we can just update this. So we can say text section. And we can define, let's say,
let's say three of these later, it's going to be dynamic based on the types of text sections that
we have. But for now, we'll just define a finite list. And we're going to say import text section.
Cool. So this defines three red boxes pretty useless. So what we want to be able to do is for
now customize the background color, even though we're not going to use it. In our final screen,
this background color property, I just want to show you how you can define parameters. So how
to parameterize, a stateless widget or really any widget. So if we want to pass in a color, first
off, I define a private member, private, meaning it shouldn't be accessed outside of this widget,
it's just something that this widget should know about. And to do that, I say the type of member
it is, which is a color. And I have an underscore for the name of the member because that underscore
means that it's going to be private. So I'm going to say color. And to customize it, I'm going to
create a custom constructor. So a constructor, lets me customize how I instantiate this class.
So I'm going to say text section, because that's the name of the class. This is how you define a
constructor. And well, what I could do is there's there's two types of parameters for constructors,
there's in Dart, there's optional parameters, and there's named parameters. So option optional
names, ones and positional sorry. So we're going to find to keep it simple positional parameters,
meaning, if I say color, here, you know, we all will basically how we use it is in location
detail, I'm going to say colors, red, colors, green, colors, that blue. And it's positional
meaning based on the, you know, this is the first argument, it knows that it's going associated
with this parameter simple. And then I could say this dot underscore, color equals color. So this
means it's kind of like same thing in JavaScript, where this means it's referring to the instance
of this class. So I'm going to say this underscore color, and it's going to give me the value of that
parameter, it's going to assign it to that. So in Dart, there's a shortcut to this, this positional
parameter. And I don't have to define the method body here, I can just say, this dot underscore
color. And what that does is, for a positional parameter, it's going to take that value, and it's
just going to automatically make an assignment to the member here, this value. So whatever,
I pass it as the first argument here, it's going to assign immediately to this color. So that's
pretty cool. So finally, we're going to refer to our member here. So it's customized, we're
going to hit save. And let's see what happens here. Cool, it worked. Um, what else we want
to cover? Yeah, that's a bummer. I mean, the last thing that you should do is, say that this private
number is final. And what final means is that once you set it, you can't change it. And that's really
nice, because it makes anyone reading the code, know that they shouldn't change it, they can't,
because the compiler will give you an error. And we don't need to change it after that assignments
been made. So I just see final here. And that's just like a best practice. So that's it. Later,
we're going to add some real text, we're going to style it. We're going to see now how the layout
is is defining how the text is constrained. But for now, it's pretty simple. And I hope
you have a good idea of main axis lamb and cross axis alignment. And if you want to do like some
bonus work, changes to a row and try that out, or play with the different options you have here.
So let's continue on. Hey, everyone. So in this video, we're going to cover how to add images to
your app, and it's pretty simple. There's two main ways to do it. One is to use an image asset or A
URL of an image. So in this video, we're going to first import an actual image asset, like a file,
like a JPEG file to our app, and we're going to include it in our pub spec yamo file,
and then we're going to implement it. Later, we're going to pull the image from a URL. So this should
be pretty simple. But we're going to cover some things you probably don't know about yet,
like constraints and how to layout the image. So in the last video, we covered layout,
let's just kind of cover what we're review what we're gonna go over and implement in the whole
video series. So it's this detail page with a nice banner image at the top and some text sections. So
what we've done is we've laid the groundwork for the text sessions, we it just shows some lines,
which we will implement in the next video with the text and all the formatting. But for now,
let's add an image to the top and keep it simple. So to add an image of, we're going to be basically
going through the blog post for this video. So if you want to look at the notes, I will be showing
the notes as we go along. So you can read along, we're going to create a new directory called
assets, images. So assets is anything like font files, images, anything of that sort, and they're
all going to be in one directory. So that's how we're going to organize things. And we're going to
use JPEGs. And yeah, that's it. So you can follow along if you want to check out this branch of the
code, or you can code from step two on your own. So what I'm going to do is off to the side, here,
I have an image already that I'm going to copy and the image are going to copy, if you check out
step three of the code, anything from step three onward has this image. So I'm just going to copy
it here. And it's off screen here, you're not going to see it. But I'm going to copy it to
the following directories. So in my code, here, I have my main root directory. So I'm going to hit
this button at the top New Folder. And I'm going to create a new folder in the root of the project
called assets. Oops, let me move here. So assets is going to be alongside the Android directory
and the iOS directory. And then I'm going to create a new folder called images. And we'll
have other folders there later. And then I'm off in the video, I'm going to in another screen here,
I'm just copying the actual actual image file. So I'm getting it from my code on branch on the
branch that I have at the repo, the link to the repo is here in the blog post. And it's in step
three. So I've already copied it, and let me show you the fact that it is copied. So since this is a
tourism app, it's going to be of all Japanese locations, just I just decided to pick that
randomly. So this is a location in Japan, and this is the image file. So later, we're going to load
it from a server. So now that I have my images there, I can't just use it straight away, I have
to go into my pub spec yamo file. And let me hide the code here. And so the pub spec yamo file is
like a configuration for your project. It's in the root of the project, could see the filename there,
and you get to list like what packages you're going to use and all of that. We haven't added
any packages yet. We'll get to that in another video. But if you scroll down here, you'll see
that there's some example configurations you can enable. So in Dart to comment something out there,
they use this pound symbol, right, this number symbol here. So if you just comment it out,
you'll actually be able to use that config. And so the important part is to configure this correctly,
so that'll work or else. If the formatting is messed up, it may not work. So what we're gonna
do is say, it says here in the description to add assets to your application, add an assets section.
So we have to have this line here and it has to be indented properly. So the parent of this is
flutter. And then assets is here. So it's indented by it's indented here. So like that you can't do
this has to be like this. And then we're not going to include specific images, we're going to just
include the entire directory. So we're going to say, for all the assets we're using, we're
going to say what the path to the actual images directory is and then that is assets slash images,
and then make sure to include the slash at the end. That way, flutter knows that you can include
all the images there. So it's going to look like this. This is the blog post, you can see a note,
we're going to want it looking like this. Another gotcha is you want to make sure that this is
indented as well. So the actual directive here is indented properly. So we're gonna save that.
And then let's implement the actual image. So let's see, we have the code here. So last time,
we have our we had our location detail screen. So this location detail screen,
had just three text sections, we're going to fill that out in the next video, what we're
going to want to do is add an actual image banner at the top of the screen. So it's going to be one
of our children of our column. So let's add that now. Let me look at what we want to do here. So
because we want this to be its own widget, we're going to create a new widget the same way we'd
like we created the text section widget. So I'm going to call this new widget, image banner. So
this is an image widget we're going to create in just a second. And before we have an implemented,
we're going to just code what, how we want to customize it. So what do we want to pass in to
the instantiation of this widget, which is only in basically the file name. So that's what we're
gonna do, we're gonna say, include the path to the image. So we're gonna say assets, slash images,
slash, and then the name of the file. It's kind of weird, because it's Japanese, of course. So if
you don't speak Japanese, it'll look weird to you. But that's the name of the file. That's the name,
that's going to be the name of our location when we show the text corresponding text with
that image. And know that later, we're going to change this app to be dynamic. So we're
not going to hard code the image, we're going to pull it from a web service API, right? For now,
we're just going to hard code it just get it to work. So next, we're going to include the widget
that we haven't even implemented yet. And I'm just doing this for brevity here. So I'm going to say
image underscore banner. So that's going to be the name of the file we're about to create. Remember
that in darts, if you don't know already, the the the input should be in alphabetical order.
So I'm going to make sure that this is before this and that it's underlined red, because we haven't
created it yet. So let's create it. Now, we're going to go into our location detail folder here.
And because this widget is only going to be used by location detail, we're not going to have it
live anywhere else. It's a widget that's local to location detail. If it was shared across the app,
we would put it in a separate place. So let's call the Let's name the file the same name of
the widget, image, underscore banner, and make sure it's all lowercase. And then,
since this is a stateless widget, and we're going to implement it much like we did the text section
widget we did in the last video, so I'm just going to copy this code here, just as a template. And
note that Visual Studio Code also gives you some options. And there's extensions to kind of use a
hotkey to auto generate a stateless widget really quickly. But that's not what we're not going to
cover that that's something more advanced. So let's name it to our image banner. And this is
the name of our widget here. And we're not going to want to customize the color. But what we're
going to do is be able to customize the path to the asset. So we're going to have a private member
here. And it's going to be a string called asset path. So it's private, again, because there's an
underscore here. Second, we're going to pass in asset path. So this is going to be a positional
parameter to our constructor. So that means that when the person wants to use this widget,
the first argument they provide to the constructor will be the asset path. And this Dart I if you
didn't follow this in the last video, when we use this positional parameter, and we use this dot,
and then the name of our private member, it automatically assigns the value. So really quick,
if you didn't see it last time, if we just have something like this, this would be the long way
of doing it. So this acid pass acid pack. So this is kind of the the long way of doing it,
but we can't work. This is just better to do it this way. So let's implement our image banner
now. So what we're going to do is we're going to display use the flutter widget, the image widget,
but we're going to wrap it In a container, what that allows us to do is provide some options,
other options like padding, or the height, and all that. So you're going to want to wrap your images
in a container or some other widget like that. So let's get started on that. So there's going to be
if you look at the screenshot, there's going to be a certain height to the image. So we're
going to want to expand the image all the way from to the maximum, we can go in the container, but
we want to still constrain the container of the image to a specific height. And to do that, we're
going to use something called constraints. And that's a parameter on the container widget. And
much like decoration that, you know, there's also something called You know, there's box decoration.
But there's also box constraints. And what box constraints does is it lets us provide all
these other options for how it the content in that container is constrained. So the most common names
constructor for this is called expand. And what that does is it says, Let me expand everything,
all the content in my container, as long as the height stays at 200 pixels. So to specify the
height in flutter, or Dart, we're going to use a double and a double is a certain data type,
you can see it here, that just basically it has a decimal point, that's all, that's all you have
to know. So if you can say 200, like this, but sometimes the Visual Studio code will give you
a warning, you can also do like this, but using a decimal, like a proper decimal, even if it's not
zero is probably better. And that's constraint. So that's what we'll see how it works in a second,
but constraints is going to say, expand all the content until the height is 200,
we're going to have a decoration. And we're going to give it a decoration of a background color.
We've already covered this in the other video, where you just say gray here. The reason why we're
giving the container a background color is because later when we loaded as a from a URL, if that URL
fails to load the image, we still want to show some kind of placeholder, not just whitespace. So
that's just the decision I made. You don't have to do that. So the child now is going to be the image
widget. So we just say image. And to use the image widget, we're gonna use also a named constructor.
And remember, a named constructor is goes like the name of the widget, and then dot and then the name
of that constructor. So there's, as you can see, here, there's different ways to name the use that
different names with constructors, you can use. One of them's asset, which we're going to use,
there's also file memory and network. So we'll use network later. But let's use asset for now that's
basically taking any asset you've specified in your postbit camel file. So we can now
just provide it the name of the asset path. So I'm gonna say asset path. And the last thing we
want to cover in this video, last main thing is how image wants to expand and behave based
on the screen size or the container that it's in so much like HTML or CSS, you can specify how it
expands and all that. And the way you do that in flutter is we use this fits parameter. And we use
this kind of value called box fit cover. So box fit, like box decoration box can constraints. Box
fit gives you additional options like that. So, fit height fit with cover fill contain,
you can use these in your free time and click into them and read about them in the documentation. The
documentation will explain how to use these but in this video, we're just going to use a cover and
cover does is it fills the image all the way as much as it can within the container that it's in.
Cool, they have something similar in CSS as well. So let's save this. There's some syntax error. So
we're going to make sure that we have the image asset finished here. And then the container
finished and let's see what else we didn't, okay, like go like this. Make sure this is finished. And
what else I need a semicolon here. That's what it was the semicolon. So I'm going to restart it. And
there we go, the image loads and it's exactly 200 pixels high. And now we can get started on
the text of our app. So that was the tutorial here. And again, if you want to read through
the blog post, it has all the code And you can read through it in your free time. And yeah,
that's it. So thanks for watching. Hey, everyone. So in this video, we're going to be covering how
to use custom fonts and flutter. And we're going to be building out our screen here, where we
already added the image at the top. And we're going to start adding text sections here. So a
tech section will have, as you see here, where it says summary, it'll have a title, and it'll have
a body. So we're going to implement that widget. And then we're finally going to cover text theming
and flutter. So text steaming allows you to define all your style in one place for different types of
elements in your app. And then that way your code is very clean, because it knows what kind of style
to pull from. So let's get started. If you want to follow along, I have the blog post here. And
to get the font files that we're going to be using the those font assets, simply checkout step slash
step 04 branch of this, the code repository, and the link is in the blog post. So let's get
started. Um, we're going to implement first, we're not going to quite follow step by step
the blog post in the blog posts order, we're just going to implement the actual text section first,
because then I can apply the font and it'll just look like nicer and be more understandable. So the
first thing we're going to do is implement more features of this text section. Because right now,
it's very contrived, it just shows colors, that's it, well, we want to do is remove this color,
and be able to show a title and a body. So let's implement that now. So instead of color,
we're going to implement two private members, one is title, and one is body, we're going to update
the constructor. And this, so this dot body, so whatever you pass it in pass in here as positional
parameters will be assigned to these members. And then let's basically define how we want our widget
to be structured. So this, each widget can have its own layout. So in the location detail screen,
we do use something called a column, we already covered that in the layout, video, but each text
section will have its own column, because content is laid out from top to bottom in a column format.
So it's going to be summary and then this body of text. So instead of container here,
let's implement a column, and it's going to be its own column, main axis alignment is going
to be start meaning the each child is going to be laid out from top to bottom, sequentially
without any pattern, cross axis alignment will be stretch. So I wanted to stretch to the full width
of the container. What we're going to do is remove decoration, we don't need that. And for child,
I'm going to have some text here. Well, we have to say children, because it's going to be a column,
and it's going to be a list of items here. And we're just gonna have title, and then the other
one is body. Then we're going to end our column. Nope, we already did here, and and our children
here, hit save. And then we're going to there's an error, because we have to update our location
detail screen to use that. So we already have text section imported here, we don't need to do that.
And now we're just going to say, well, hard codes and values in here. So we're gonna say summary,
something one, and then something to something three. So later, we're going to make all this
text dynamic, it's going to pull from a web server API, web API running on a web server somewhere.
And it we're not going to hard code anything like the image names and all that. So cool,
it looks really boring, because there's no formatting to it. So let's cover that next.
First thing we want to do is add padding to each of our widgets. So to add padding to each text,
bit of text here, we're going to wrap each text widget in a container widget. The container
widget lets us define that, that the text doesn't. So to add padding to a container,
because we want to control the different padding schemes, so we want to control padding on the left
and right and the top and bottom and it's going to be different for each we're going to say const
which is a constant edge in sets. And then from lt RB so that's a special named constructor for
edge in sets and lets you granularly define all that padding. So because this each day This text
section widget is going to share the same left and right padding, I'm going to for simplicity's sake
define a constant up here. And it's, well, it's, it's going to be a static constant. And I'll get
to that why it has to be static in a second. But we're gonna call it horizontal padding. And for
just brevity, because I use the slot, I'm going to say h pad. And people usually will figure out
what that means. The reason why it's static is because since I'm using a const, here, it just
has to be static. I can't I can't, you see, if I remove it here, I can't define a constant as a as
a member of a class here, it has to be static. And that's just the rules of Dart. So for the left and
the right padding, it's going to have that value. For the top and the bottom, I'm just going to use
a custom values and then use 32. And four, you don't really need to specify the decimal point,
but I just like to because it's a double and just more consistent that way. So then we define the
padding here, I'm going to end let's see text and and my container. And then I'm going to add,
let me add my child. And then I'm going to add the other container. And it's just going to have
different padding because of because of the fact that it's a just based on the design of the app,
it's going to have different type of padding. So that padding will be let me look at my notes,
it's going to be 10. And just use the same value as horizontal padding here. Save it. So cool. Now
we have the things like nicely padded, and I'll add some more text here. So you could see it like
kind of looking a little more realistic. In the next video, we're going to add in real text here.
So let me just paste that in. Cool. So that's just really, really ugly looking text. But it shows you
that it's going to flow nicely and the padding looks okay. Okay, so let's cover the style of
the app. Before we do that though, the style that we're going to implement uses a custom font. And
so we can implement that style without it failing until we add our font file. So let's go add a
custom font. So to get the custom font file we're going to need and let me show you the screenshot
that the the font looks really nice that it's this font Montserrat, I'm going to I've checked
out the step four branch of the code, and I'm just going to copy the assets that already have,
I'm going to do that off screen here because it's just easier. And what we're going to do is in the
assets directory, we're going to have a child called fonts. So that's going to be a sibling
of the images directory. And then I'm going to just paste it in here off screen, and boom,
okay, so the fonts got added. So each font file, I downloaded these from Google fonts, each font
file has a special like family name. And what we're going to do is in our pub spec yamo file,
as you remember, the public ammo file lets you define packages that we're going to cover that
we haven't used the custom package yet. It lets you define where your image assets are. So here,
assets slash images. But for this video, I've implemented this already, which you're going to
have to type in yourself or copy from the example code, we can define a section called fonts,
and it has to be indented properly. So you just do one indentation, because it lives under the
flutter section. That's very important. We're going to call it Montserrat. So the family name
you define here is the family name, you'll refer to in your style when you define styles. So for
each font file, I can specify the weight I want to use. So for this file, it's going to be 300,
which is kind of like regular light slash regular weight. And then 600 is kind of a bold weight. So
we're going to have two different weights. So make sure you save that. And the indentation is
all proper. It's like using two spaces for each section. That's how YAML format ml is defining
indentation. So how do we use these fonts? Well, one thing we can do is in our text section we can
define in each text widget, just to get something to work, we can just say style. And then we can
define text style. And then we can define all kinds of parameters for that style. But for just
for cleaner, simpler code, we don't need to do that verbose way of doing things because that's
going to get very repetitive. Where we want to do is to find one single style throughout the
app. And it kind of works like CSS as well. And to define the style throughout the app, because we're
using a material app widget, the material app widget gives us these shortcuts. And one thing,
let me look at my notes here. One thing we can do here is define something called a theme. So this
is how we use themes in flutter. So the theme is something general. And there's different types of
theme. So we're gonna say theme, and then theme data. And theme data lets us define various how
various widgets are styled in the app. So the first thing we're going to define is the app
bar theme. So the app bar is a material design terminology for the navigation bar at the top. So
for iOS users, it's called the navigation bar. So we say app bar theme, and you instantiate an app
bar theme class. Exactly. And so that app or theme class is going to give you certain parameters. One
is the just basic text theme of the navigation bar at the top. So let's define a text theme.
And the text theme we instantiate here. And for the title of that text theme, there's different,
there's different options you can use for text theme, you can go over it in your free time. But
these are the different. These are basically all the main options for a general text theme. And I
won't get into this too much. But for the sake of brevity, in this video, I'm going to find
the text theme that I want to use. And instead of hard coding into my file here, I'm going to
define the the text theme in a separate file. So it's nicely organized. But for now, I'm just going
to type in what I want to implement. And that's going to be at bar text style, this is going to
be something I defined as a custom thing. In just a moment, I'm going to now going to implement it.
So to organize your style properly, what I personally typically do is I create a file
called style dot Dart. And that style dot Dart is going to define all the style of my app. And
what I'm going to do is import material. And I'm going to define some constants at the top because
I'm just going to paste it in here. And what this does, it lets me keep my style file very succinct
and clear. So I'm defining specific different categories of text sizes. And then the name of
the font I want to use. This is the core family name I defined in my pub spec yamo file. So I'm
going to paste this in here, this is going to be my app bar style, it's going to be it again,
it's a text style. And it works. Again, it works a lot like CSS. So it's very easy to follow. It
has a font family, so refers to my font name, Montserrat, a weight. So for font weights. In
flutter, you can define different font weights. So they all go from 100 to 900. And because I defined
one that's called 300 in my pub spec, yamo file, see here, I can use that weight. So that's the
font weight, and then the font size, it's medium, it's 20. And then the colors, it's just going to
be kind of white, because the fact that I have a colored navbar up here. So I'm going to save that.
And then I'm going to import it in my app dark style dot Dart. I'm going to save it. And cool
now our navbar is styled with the custom font you see it's kind of like lightweight here. And we'll
we'll style it more later. Because that's not this is not quite the final design we want to
use. But we'll we'll continue with this later. So let's finish up the style of our app. So now that
we have the app bar theme, the adaptation is a bit strange looking here because of the way auto
format. But for me do this so that you can read it better. And the last style we're going to define
here is our style for just basically the text section. So I'm going to go look at my notes here.
So for the text theme, we're going to define, there's various text theme that throughout the app
that we can define here. So texting could be for various different components. So one is for just a
loose something loosely named called title you can I'll show you how to use it in a second. But it's
basically for any title you use. So we're going to call it a title textile. We're going to implement
this in a second because this style same with the app bar text style will come from our style file.
And then we're gonna say body one. So body one is just another Name we're going to refer to later
in our code. And that's for any body text body style, we're going to call it body one text style.
So let's implement this now in our style file, so and our style dot Dart, I'm going to paste these
in. First off, I'm going to paste in the title, textile. And the title textile is going to be
looking like the same thing, but it's just going to have a black color. And that's going to be
large. The next one is body one textile, same thing, but it's just going to have a different
text size. So body text size of 16. So now that I pasted those in, and I have these defined here,
the general style for all the text in the app now is changed. So it's going to use the basic font of
the style, but there's certain elements about it that are not going to be used. So for let's say,
the title textile, it's not going to use this. certain elements of this, so it's not going to
be large yet. So to to kind of deliberately say, hey, for this title here, let's say summary, one,
I want to use the title text style, I have to deliberately go into my text section widget. And
we're going to have to update that. So how we're going to update that is for here, we're gonna say,
for the text widget style. And then we're gonna say theme, use the name constructor of,
we're going to pass it our context. And again, our context is something we pass around in the app.
And it just is a way for flutter to kind of know certain, certain contextual information about the
rendering tree, the widget tree. And now we can refer to any style that we have defined here. So
we can refer to text style text theme rather. So because of the fact that we defined a text theme,
I'll go back to here, here. So in our theme data widget here, we defined a text theme. So now we
can use it. So I could say theme of context, text theme. And now I can specify exactly what subset
of my text theme. So I'm because I define a title text theme. Again, going back to App dot Dart,
see, I defined a title, text theme, I can use that now. So I say title here. And I'm going to save
it. And now it's using the actual text theme, I want it It's the exact text size that I wanted to
use all along, I'm going to do the same thing for my body. And so I'm going to paste this in here.
And I'm going to say body one. So basically, it's not going to be I don't have to do this, because
it's already taking the style of that because this is just normal text. If I define a text theme of
body one, all the just general text of the app is going to be styled like this. But I'm still
defining this style here. And I'm using explicitly body one. Because it's just more explicit that
way. It's clear. And but you don't have to do it like that. So yeah, that's, that's how you
style text and flutter. I think that wraps it up for this lesson. Yeah, and we're going to just,
you know, style this more later. And then the next episode, we're going to actually use dynamic text.
So we're not going to hard code anything in. Um, but yeah, that's it. So thanks for watching. Hey,
everyone, Nick here. So in this episode, we're going to talk about three things. One is how to
use models to represent data and functionality. And we're going to update our code to make our
screens dynamic, and not hard code, any data in there. And also, we're going to be covering
Dart concepts such as generics, the map function, anonymous functions, and cascades. So if you want
to follow along, I'm going to be going through this blog post as I go through the lesson. And
you can find the blog post on flutter, Crash Course calm, and then go down to the episode
working with models here. If you want the code there, the links in the blog post right here,
you have to just check out this branch here I have highlighted to half of the actually have the code
we're going to be implementing. So let's talk about the significance of the apps data model.
So a data model is something very, very generic to any kind of app. It's not only flutter apps,
it could be web app, just a traditional software application or could be a mobile app doesn't
matter. So a model is basically a glorified class in darts. So when we have an app that we're going
to write, the app usually has input and output. So like any software program, so the input of the
data is going to be probably some data we fetch from an API somewhere. So it could be a Firebase
API or a normal traditional HTTP based restful For API. So that's the input to our app because
the data is coming into our app. But the problem is we need to when we take that data into our app,
we need to represent it somehow in memory. And that data might be complex and might have
different types of data with different types of fields to it and properties. And also that data
might relate to each other in different ways. So let's say we have our tourism and co app here,
the input of the data would be a list of locations that can be shown to the user. And each location
could have a list of facts of that location, like fun, interesting things that you want to show to
the user. So if we want to represent that data in our app, we're going to create two classes,
a location class and a location, fact class. And we're going to have a relationship between them.
So the model also represents the relationships between different pieces of data. So the location,
model or class, if you will, will have a list item, a member, that's a list of Dart list, that's
going to be a list of facts. So there's a one to many relationship between location and location
fact. So all of this data taxonomy and all that stuff we're going to represent in classes, and
we're going to call them models, that's just like a terminology that a lot of people use. So when
we fetch the data from the API, we're going to write certain code that creates instances of the
location class. And when we want to use that data, in our app, let's say we load a given screen,
let's say we load a location detail screen, we can easily work with that data if we have them cleanly
separated into separate model files. So So again, scrolling down here, we have the models location
and location fact that we're going to create in the lesson. And again, it's going to be a one
to many relationship. So that's more coming from database design terminology, one to many and all
that stuff. But that's just like stuff that you should know as well, you could use that not only
for databases, but also for how your models relate to each other in your flutter app. So this is how
we're going to use our models I'm scrolling down here. This is how it is a given use case of how
we're going to use our models. So our app loads. And then, since we don't have multiple screens
yet in our app, we're going to do that in the next lesson, we have a single location detail screen,
it's going to load, we're going to say, hey, just give me like from a list of given locations, based
on a location identifier, or ID, we're going to also add that in this lesson, give us the name of
the location, and then render it in the navigation bar. And then for each location fact, again,
it's a one to many relationship between location location fact, render a given text section and
on our screen. So right now, as you can see, in my simulator, I have three text sections. That's just
hard coded. So what we're going to do is update the code to render a given tech session based on
each fact we have associated with that it could be one fact that could be five facts, it depends
on the location instance, we're rendering. So how do we add our models. So basically,
I'm going to show you the best practices for when you're adding models, where to add them,
and also how you can use code commenting and what the best practices are to make sure that if anyone
else is reading the code that it's easy to read. So let's get started. The code example that we're
going to code is in this blog post, so I am going to open my basically, I'm going to open my code
here. And I'm going to explore here, and I'm going to create a directory called models. So basically,
in terms of code organization, best practices. In the lib directory, there's going to be a sibling
directory, two screens, the screens directory that we have, and we're going to call it models,
then we're going to create a new file called location Dart. And now we can increase the size,
we can just implement our location model. So it's going to be again, a class and each class in Dart
is going to be in title case, meaning the first initial of every word is going to be capitalized.
And I'm going to have three fields here, I'm going to have string, I'm going to a location has a
given name, it's going to be let's see image path. And then it's going to be a list of location facts
final list location fact and I haven't created that yet. So it's going to have an error here.
Fax and then I'm going to update a constructor so that I can create this model very easily. So we've
gone over this before, but we're going to use a short Cut here, where if we use this dot name,
this dot image path, and this dot facts, we can, the constructor will automatically assign the
values you pass in to your members. And that way, we don't have to actually implement the the class
like the constructor like this. And we've gone over this previously, so I won't go over that too
much. And then we're going to import which a file we haven't created yet. Location fact dot Dart,
make sure that the name of your model is in single case, like a location because it is one given
location. So don't make it plural. And also, that goes for the file name. So I'm going to create a
file name called location facts, not facts or anything like that. It's a one single fact. And
a location fact, again, its title case, let's see what we want. It's going to have title and a text,
let me just paste this in because it's faster from the blog post. It's not rocket science here. So
location facts gonna have title and a text. And that's really it. So no errors are here. That's
great. Um, so yeah, let's see. So let's talk about how we're going to add business logic to
our model. So business logic, again, is just a glorified term for just some code. And there's
some rules to that code, based on your business or your what you're trying to accomplish. So we're
going to implement that. And one traditional way to implement business logic is you can add them to
the model directly. If it's not such a big app. If it's not, if the kind of a small to medium
size app, a lot of people just add the business logic and core functionality to their models. So
let's say I want to get a list of locations, I'm going to add a method that fetches those
locations. And I'm going to add that method to the location class. So um, that's pretty much a common
approach. So in this method, here, I'm going to implement that it's going to I'm going to paste
this in, because there's a lot of code here. And I, I suggest you not typing it in because it's,
it's tedious, you can just check out the code here. Let's go through this. So this is going
to be a function that's static and, and static, meaning you don't have to instantiate location to
invoke the function, you can just say, fetch all so this is going to be a function called
fetch all, it's going to fetch all the locations in our virtual database, it's hard coded now,
but in a few lessons, we're going to fetch it from an actual back end API. So we're gonna say fetch
all and this is not a realistic fetch all function because usually, you would add like a, you know,
pagination parameters, a fetch from one to 10, or whatever, or fetch numbers 10, to 20, or all that,
but this is very trivial example, and it's going to return a list of locations. So each location
we're going to call is the constructor, we're going to pass in a name here, and this is the
path to the image and all these, and then it's going to be a list. And for each list item,
we're going to instantiate a location fact. So this is going to be summary how to get there,
etc. So it's really ugly now. But once we have an actual web service API hooked up, it'll this
will all go away. And also note that for now, we are using this kind of ordered parameters
for our constructors, there's, if you're having a lot of parameters, that's there's another way
of doing that we'll cover in another lesson. But for now, this is like the simplest way. Great,
so we have our models. Let's continue. So let's make our code dynamic now. So we're going to take
and use this fetch all function, and we're going to update our location detail screen. So let's
import the location class. And we're going to update the following. We're going to update
the app bar title, we're gonna update this image banner and then we're going to iterate over every
fact of every of the location, we're going to load and render a given text section. So how we're
going to do that is simple at first, we're going to load all those locations in the build method.
So we're going to say location dot fetch all and then we're going to assign a given location. So So
for a given list locations is a list type. There's a special kind of property called first and that's
just like saying, like this, basically, and right now we don't have multiple locations, we're
going to implement the next lesson. We're just gonna assume we just have one location because
we're just loading a location Details screen here. In the next lesson, we're going to pass in
an identifier to location Details screen and then loaded by identity. to fire. Another word before
I continue is that um, usually you don't want to load data in the build function because the build
function of any widget can be called multiple times. So we don't want to be doing that. But
just to get it to work for now, we're going to be doing it here. And I'll explain in later lessons,
how the kind of ideal way to do it. So now we have access to our given location. So I can update the
title here. And I could say location dot name, because location has a name property, as you can
see here, this is the name property. And then I can say in the image banner, say location dot
image path, that's the another property here. So let's reload that. And it looks like it's working
pretty well. So what are we going to do with each text section. So basically, um, in Dart,
there is a special function called map. And what a map does is it converts a list or an array in Dart
is called list of stuff to another list, but but of another type of data. So if I have a list of,
let's say, strings, I can use map to convert it to a list of actual objects, like a list of widgets,
right? In our case, what we're going to do is we're going to have a list of location facts,
which is an array of I'll show you the model, it's going to be this data type list of location facts.
And, again, just touching over this again, this is what we call generics. So we've went over this in
the last few lessons, but I want to refresh real quick before I continue, it's going to be a list
of location facts. So generics is basically the ability to define a given type for specifying the
type of something so you have to specify a list of something, it's a list of string, you could say
list of integers. And in our case, we're gonna have a list of location facts. So that's what
generics is. Anyway, where the map function was, we're going to say, for a given list of location
facts, we're going to convert that to a list of widgets of type text section. So that's what
map does it transforms of one type of list into another type of list? So how are we going to do
that? Let's make a function where we're going to take all this stuff, we're going to cut it out.
And we're going to say, some list of widgets. And, and then we're going to just add it in here, after
the fact. So before we do, go ahead and do that, let me implement a function that returns that list
of widgets that implements our map function. So what we're going to do is, we're going to have
a list of widgets, that the function is going to return. And let me look at the code real quick,
what are we going to call it, it was called text sections. So the blog post I just brought up has
the kind of final implementation, but I wanted to do it from scratch here. It's gonna, it's going
to take a single location. And that location is gonna, we're gonna say location dot facts. Again,
it's a it's a list item. And we're gonna say dot map. And dot map takes a what's called a
anonymous function. In other words, it's another word for it is a closure in Dart. And a closures
are something very pervasive through other programming languages. And the syntax is just kind
of weird. A closure or an anonymous function is a function, but you don't give it a name. It's just,
it's anonymous, you don't have a name for it. So f is our function. And we're going to implement
our function right in here. So the function because how map works, the function will take
one single parameter, and the parameter is it's a given fact. So anonymous functions in Dart have
three parts to it. The first part is the actual list of parameters of the function just like any
other function, this is the list of parameters. And the number of parameters that's available is
defined by this actual map here. So we know that if we click into it, this is pretty cryptic. This
function that it's defining that we pass in will only allow us to have one kind of parameter, but I
would look at this as is pretty complex. Anyways, the list of parameters, and then there is a arrow
here, it's called rocket notation or something, which is saying, Hey, we wanted to find a
single line implementation of our function. So in theory, we can do this we can use curly braces and
implement our function here. But with this arrow does is it lets us define if it's the function is
a single line, it lets us define the function as a single line of code. So we can say no Whatever
we define here as a statement, it returns. So we can, if we want to return, let's say FUBAR, it'll,
we can do it like this, right? So what we want to do is the implementation of this is return a text
section. So remember, we had a text section widget here. And that's what we're going to implement. So
text section. And then for the fact, we're going to have fact, um, what is it, a fact has a title
and text. So fact, title, and fact text. So this, again, as I said, just to go over this one more
time, because you're going to be using this a lot in flutter apps is map will convert a list of one
type to a list of another type, right? So in here, we're going to, it's going to iterate each fact,
in the facts list. And for each fact, we're going to execute a single statement, as denoted by this.
And that statement is going to return what's going to be pushed into the new list. So it's
going to return a text section. And we're going to re implement the instantiation of our text
section. And then it's going to return it. So this is going to return a iterable kind of list
of stuff. So iterable of a given type. So iterable is another thing in Dart that's kind of a kind of
like a parent grandfather type of something that you can iterate over, it's something generic,
but we're not going to be it's not useful to us. So what we can do is, we need to get get a list.
So for iterable, we can just say to list and to list, we'll convert something that's iterable
to an actual list type here. So yeah, that's it. That's the implementation. Um, we return
this. And then we need to use this list of tech sessions read return here. So we can't just call
text sections like this and pass in location. Because we want to add, because this is a list,
we want to add it to the existing list of it, we want to inject it into our list here. So
this is already our list, we want to inject it here. And basically, we're going to do this,
we're going to use darts spread operator. And it's called the cascade spread is coming out in the
next version of Dart. And, and that's different. But cascade is two dots. And what cascade does
is it takes a given item, and it lets you run a function against it or, or make an assignment or
do something else. So I'm going to say the cascade operator. And then we're just going to say, add
all. So I'm going to, there's a special function in Dart called add all. And what that does is, it
depends all objects have something that's iterable to the end of the list. So if we have a given list
here, it's we're gonna say at all, and then we're going to pass it a something that's iterable. So
text sections is iterable. And that's where we're going to do. So there's a lot to unpack there on
the, but like, this is kind of a common situation. in Dart 2.3, which is coming out very soon, you'll
be able to use a nother operator called the spread operator, which is three dots, and kind of kind
of tack on list items like that more easily. So anyway, let's reload this screen. And yeah, there
we have the text here. So all the text looks nice here. And that's it. Um, let's see what else we
have to cover here. So if you want to go over what cascades are I have links to what cascades are I
have a I have a link to what the map function is. Well, I have notes on it. But I also have
a link to the actual documentation in the in the Dart website. So this is a link to it. And yeah,
like, you know, I would say play around with this stuff. And in summary, basically, I guess that's
what we cut. That's all we need to cover. So our app now dynamically adapts to whatever data we've
defined. So in the next section, next lesson, we're going to be covering more advanced features,
and building out a new screen. So thanks for watching. So in this episode, we're gonna be
covering navigation in flutter. And also the list view widget, which is a really important widget.
Because most apps are made up of some kind of ListView of stuff. It could be newsfeed items,
photos, whatever. So finally, we're going to be covering gesture detector also. So we're going to
be implementing the second major screen of our app, the tourism co app, and You'll be able to
browse through a list of locations and tap on one to get to this detail screen that we've already
implemented here. So let's get started. If you want to follow the code and and just get a copy
of the code we're going to be implementing In this lesson, you can check out the repo at this blog
post on flutter Crash Course calm. It's called navigation in flutter. And there's a link for
the code for this lesson up here. And you have to check out the branch step slash step 06. So
first thing we want to do is update our fixture data. So fixture data, again, is just test data.
But we want to show a lot more locations. So we can show this list view widget easily, we're also
going to add a new field to the location model, which is ID. And what Id is going to do is,
it's a unique identifier that lets us pass around in our app so that we can load a given detail
screen. So if I tap on location with ID two, for example, I then make a call to my back end to say,
hey, fetch me all the data for location too. So we're not integrating with the backend quite
yet. But that's the kind of code we're going to implement before we actually do that integration
just to wire things up. So you can check out the branch to just copy and paste this new location
data if you want. I'm going to do that right now. So let's open our project. So the we're
going to open the location model. And right now we only have one instance of a location. So we're
going to want to create three. And before we paste that in, I'm going to actually implement this ID
member. So int ID for location, and it's going to be an int. different apps do use different forms
of identifiers. Sometimes they use a string as a COVID. But in our case, we're just going to use an
old fashioned just into, so we have to update our controller here, our constructor rather sorry. And
then I'm just going to paste in what I have here to the side. And that'll be a lot easier. So boom,
done. That's it, let's make sure we have the images in our app. So every location refers to
an image. So an image file locally later, we're going to be loading it from a URL. So right now I
don't have all the images. So I'm going to have to take the images from an exhibit the ranch called
step slash step 06. And I'm just going to copy it now off screen. So I've checked it out off screen,
I'm going to copy it, and then I'm going to now paste it into the assets directory and the images
subdirectory. There. So I'm going to paste it in and boom, they show up right here. So make sure
you have these images here or else they won't show up. Great. So let's go back to my blog post. So as
you know, in every lesson, I follow my blog post, so if you want to see the show notes,
you can as I talk, let me increase the size for you. So our fixture data is done. So next thing we
want to do is implement a new screen, which is the location listing screen. And this is going to be
a stateless widget because it's not going to need to maintain any state. And it's going to also use
a scaffold, which is that it's that convenience widget that lets us create a new screen. And we're
going to create a ListView inside of it. And a ListView basically takes in a list of items,
whatever that is, it's just a bunch of data. And it will render those items and automatically
scroll let you scroll those items. If there's you know, if it overflows the screen. So this
is the boilerplate, as you see in front of you for the list, how we would use list view,
we would basically fetch all of our locations and pass it, map them. And we've covered map in
the last lesson. So if you don't know about that, check it out. And for each location, we're going
to display the locations name period. And that's it. And then we're going to return a list for the
list view. So let's continue on here. I will just implement it now. And we can build upon
this so we can add an image or make it tappable or whatever. So let's actually implement this. Okay,
let's continue here. Um, so open the so the screens directory It shows all of our existing
screens right now there's there's one folder per screen, we already went over code organization. So
this is how we're going to continue to organize our code. So I'm going to hit New Folder. And
we're going to call it locations. Because it's basically a list of locations. And for naming
your screens, you want to basically name them as simple as possible. So you don't want to
you don't want to name it location listing, it's just too verbose. You can if you want,
but it's just too verbose. So I'm going to call it locations. And because it's the main screen, I'm
going to name it the same name as my directory. And that's really important to be consistent. So
let's start implementing this. I'm going to paste in the boilerplate code for a stateless widget,
and also our imports. So I need to import app dot Dart and also the location model. So in terms of
the simple screen, pasting that in, we want to use a scaffold. So I'm going to paste that in
because we already went over this before, let me increase the text size for you. So and then
I'm going to hide the left panel here so you can see it better. So the scaffold takes in a body,
as you know. And let's go ahead and implement ListView. So we say ListView. And so there's
different versions of ListView. You can use right now we're going to use the traditional ListView.
constructor, there's some named constructors we're going to use later but we'll cover that. So if
you're used to list view already in your, you're implementing it in a different way, just like just
follow along and, and just see how I implement ListView. Because the main way to implement it is
there is a children parameter, and that children parameter takes the list of a list of whatever
you want to render. So it's going to be a list of widgets at the end of the day. And for now, we're
going to make it really, really simple. So let's go back to the example in the blog post, right,
now, we're going to just implement a list of text widgets. So let me when I fetch my locations,
I'm gonna say map. And map takes a is basically an anonymous function. So So for each item in the
map, which is a location, I'm going to execute the following function, and that function is going to
return a widget that represents each item in my list view. So I'm going to return a text widget.
And I'm just going to use the location name for the text widget. And then finally, I'm going to
convert it back to a list because map returns an iterable type. And that's more of an advanced type
that you don't really need to know about right now. But you just have to convert it back to a
list because that's what children is, it's a list of widgets. So we have to say that, and let's see,
I guess that's it. Let's see if that rendered. So I have my emulator open here. And we have the
detail page open now. So now we have to update the app dot Dart to kind of show this view right here.
So let's go to App dot Dart. And a shortcut for opening things in VS code is command p,
or if you're on Windows or Linux, it's Ctrl P, and then you just type the name of the file. So
that's really useful. So basically, the homescreen is now not going to be location detail that was
just there. For example sake, it's going to be now location. So let's update our imports. And
I'm going to update this, save it. And now let me let me just do this here, bear with me. That way,
you can see the code on the screen here. Cool. Now, this is a very basic list view doesn't look
really cool. It just shows like a single name. And that's it. There's nothing fancy about it.
We're going to be adding an image for each item here later. So Oops, I'm going to show you that.
So I have the mock up of like the actual end result of our app here. And I've showed it
to you before. Let me open it for you here in a new window. Because it's not let me show it
to you. Let's see location list. Yeah. So this is going to be our final ListView, we're going
to implement the list view is going to have one image per item. And it's going to have a widget at
the bottom with with the name, the opening times of the location, and just the some subtitle. So
that's what we're going to get to so we're not going to render those images quite yet though,
so great. Now let's we let's cover how to interact with an actual list view items. So we're going to
implement a gesture detector. And the gesture detector is something very basic in flutter.
Most other widgets already include the ability to detect a tap, it could be in the form of a button,
or whatever. But a gesture detector is the kind of parent type that's can be used for really
any widget. So we can wrap anything with a gesture detector and actually pass on an anonymous method.
And that method can do whatever we want. And in this case, we're going to navigate to the location
Details screen. So let's implement a gesture detector. So basically, to implement gesture
detector, it's it's its own widget. So because it's, it's just a widget here. Let me just do a
word wrap here, wrap. Great. And I'm going to hide the left bar here. So it's another widget. So we
can wrap the text widget here with a gesture detector. And a gesture detector has a child,
which is going to be the actual thing. And let's see child text there, and then and the parentheses
here and save it, it's going to automatically format. And it's not going to do anything yet
because we have to implement a new kind of parameter here. So instead of only providing
a child, there's another parameter you're going to provide, which is called on tap. And on tap takes,
let's click into it to see how you implement that. An on tap is a type of gesture tap callback. And
if you type tap into gesture tap callback, if you click into it, you're going to see it's just going
to be a function a general function. So you can click into this as much as you want to see how
things are implemented. But just trust the process for now that it's it's going to be a actual
function, anonymous function. And let's implement that now. So because it's just a generic function,
it doesn't take any parameters. So we're going to do the parentheses here, because without any list
of parameters, and then the arrow here, the rocket notation, and now we're going to implement the
function for on tap. And because it's a little bit more complex, we're going to pass it the name of
another function so that we're not implementing the function right in here. With like a block,
it's going to just get too messy. So we're going to implement a function called on location tap. So
it's really important to name your functions very explicitly. So we're tapping a specific location.
What's not ideal, in my opinion, is to name it something like handle tap, or handle location tap,
well, I guess the handle location taps fine. But on location tap is something a little more
concise. And it's already like explicit that it's a handler. So on location tab, um, I think is the
best terminology. And it's important to be good about terminology when you code something because
it makes sure that your code is nice and concise. Okay, so let's implement this now. Um, it's gonna,
we're gonna pass in the context. So as you're gonna see, in a sec, we're going to need to use
this context variable. And what we're going to do is pass in the ID of the location,
what's important is, we're not going to pass in the actual location, because in Dart,
it's going to make a copy of that location instance. And that's not really memory efficient,
what we want to do is pass only the absolute minimum data we need to any function we're going
to use because because we don't, again, we don't want to copy actual entire object instances. So
we're going to do that. And let's implement that method right now. So because this method doesn't
return anything, we can say void on location tab, but what I usually do is I just leave
out the void. If it's returning void, you can just omit that. And it passes a build context.
And then the location ID. And so what this is going to do is going to know navigate to the new
screen. So now let's talk about navigation next, before we actually implement it. Okay, so before
we start any implementation, let's just talk some navigation concepts. So in any mobile app,
navigation works like a deck of cards where every card in the deck is a screen. And when your app
loads for the first time, it's only going to start off with one card because there's only one screen
loaded. And that is defined in app dot Dart here in the material app widget by the home parameter.
And we already went over this, but that home is the starter screen for your app. So your app just
starts and it starts with one screen and one card in the deck. Now when I tap on an item in my list
view here, which we're going to implement It's going to load a new screen, it's going to load the
location detail screen, which is another card in your virtual deck of cards. And it's going to take
that card and move it on top of the other card in your deck into the view for the user. So that
you're pushing and popping cards at the end of the day. So it's basically in computer science terms
of stack. And that stack, you can push more cards on top of the deck. And the card on the very top
of the deck is what shows to the user and when you want to go back. So let's say they tap the Back
button, that card slides off the top of the deck, and the previous screen is still there for the
user. So the previous screen is still in memory. So when we define a series of screens in our
app in flutter, and a lot of other kind of mobile frameworks, you're defining a list of what we call
routes. And that borrows from web app development terminology where a route is a basic URL that
is a path to a page. So the home page route is just slash. Another screen route is like slash,
whatever. So in flutter, you're defining routes, and these are called named routes,
because for every route, you're giving it a name. So let's define that. There's a parameter here in
material app called routes. Now, ultimately, we won't be using this parameter, because I'll show
you the shortcomings of it. But for very simple applications, it works really well. Because if
you don't have any kind of like fancy context, you want to pass to your new screen, it works fine.
And I'll explain that in a second. I'll explain what I mean by that in a sec. So let's open up
the blog post to show you the example here. And I'm just gonna copy and paste this in. Because
it doesn't make sense to type it all out. So in a very, very traditional app, when we have routes,
we have the slashes, the just we can call it whatever you want. But it's usually using slash
as the home screen. This is the first screen that loads, right. And instead of home, we can
say like initial route, and we can just refer to that route by name, because the name of that route
is just slash. When we want to navigate to another screen, we have to do first to find that route to
that screen. And that screen is like slash second or like FUBAR or whatever you want to name it,
right. And to navigate to that screen, then I can refer to that screen by name or the route name. So
I can say navigator pushed named context, slash, and then you know the name of the route. So going
back to my Detail page, if I tap on a location, I can say, navigator, which is a to basically
work with navigation in flutter, there's a class called navigator. And you say push names, which is
a named route, and you pass it the build context, and then the name of the route you defined,
very simple. Now, the shortcoming to this is like pretty clear. Because if your second screen needs
to pass any parameters, if you need to pass any parameters to it, like FUBAR, whatever like this,
right? Where are you going to get the values to those parameters? That's a shortcoming because
there's no way to define how those parameters that data is going to get there if those parameters are
dynamic. So for example, if I have the location, detail screen here, location detail, and I need to
pass the ID of the location we're loading, how am I going to know what Id that is? By
defining it up here in material route? So there's a solution that we're going to implement and it's
standard flutter, but it's not like documented very clearly. It's it's kind of a little bit
more ways into the official documentation. So I don't recommend defining routes like this,
because they're really it's just that's that's the big shortcoming to that and I hope that makes that
explanation makes sense. So let's basically take a pause, and implement the location detail screen on
how we need to load it because I can't implement a working example of location detail screen unless
we update it. Now, we went over the fact that the location Details screen right now only takes it
doesn't take any parameters. Look, it just loads any random location, right? This is my location
Details screen, it just fetches all locations, and then it says whatever first location have
just loaded. So we're not going to have to quickly update the location Details screen to take in a
parameter. So let's go do that now. So we're going to have an int as a private member called location
ID. Now remember, this is still a stateless widget because location ID we don't need this data to
react to any kind of state changes. It just loads this location ID when it loads and That really
doesn't change. So let's create a constructor now, a custom one, so that we can load the location ID
and make an assignment to the private members. So I can call location detail pass in the ID.
And then we're going to need a way to fetch a specific location by ID and then loaded here,
and we don't have a method for that. So the only methods we have in the location model is just
fetch all. So we're going to have to implement a method that closely resembles what we're going to
ultimately be implementing, which is a call to our back end service, which fetches a model by
ID identifier. So let's go ahead and implement a function called fetch by ID. So we still have
the fetch all that that's going to be used still. But I'm going to implement static a static method,
because we don't need to instantiate a location. And it's going to return a location, fetch by ID.
And that's going to be the name of and we're going to pass in a location ID. And then, what we're
going to do is, whenever you implement a function that the easiest way to implement it, is just to
write out pseudocode. So and then implement that, because it's just easier to implement. So we're
going to say, fetch all locations, iterate them. And when we find the location with the IDB wants
a kind of return, it's immediately. Of course, it's good to get this is a trivial example,
we're going to be replacing it with a back end API call. But it's it's not an efficient way of
kind of implementing this, but it gets the job done for now. So we're going to first fetch all
our location. So we're going to say location fetch all and, and then I'm going to have a for loop and
in a for loop in Dart is pretty strict, simple, it looks like a lot for loops to use in other
programming languages. So I don't need to explain too much. So we're going to say, iterate all the
locations, and then, um, locations I, so the location at index i, if the ID matches location,
Id return immediately, the location at index i. And I know you're saying we can probably load all
the locations and a map and instantly fetch those locations via a map. But this is just a simpler
example. So we're going to have now fetch by ID. Now later, we're going to be going over this is
an error because we're not implementing haven't fully implemented our screen yet. In the future,
you're going to write a natural test for this. And we'll go over testing later like that, you're
not going to just write functions, and then just expect them to work, it's best to have a unit test
for that. But that's it for another episode. Also, let's move this method down here. So that because
it's a little bit more of an explicit method, and we want to show all of this data up here, just to
make it nicer looking. So now let's implement the location detail. And the location Details screen,
we'll call this method. So we're gonna say location fetch by ID. And then we can pass it
simply our location ID, and name it the variable location, and then we can remove this. So now,
we, we will just this is working fine. We can instantiates location detail instantiates,
it has a location ID automatically and then when the screen loads, we fetched by ID Great. So now,
let's implement. Basically, we can implement push named as I talked to you about like, like,
we have to pass in an actual ID. So I'm going to now go over how to pass in dynamic arguments
to the screen we want to load. Okay, so let's implement what we're actually going to be coding
at the final implementation of this. So instead of it, we're not going to use the normal push names,
we're going to use a more extended version of push names. And we're going to pass in an argument to
push name, which is the ID, the location ID here. So let's implement that now. So before we do that,
first, I'm going to go to App dot Dart. And this is how I personally implement this. Like there's
many different ways of implementing routes, but I'm going to have two constants at the top of app
because constants allow me to define like refer to location route globally, by the actual name
without having to it just prevents mistakes. So I can refer to location name, by an actual,
like variable name and in constants in Dart should be starting with Capital letter. So this is going
to be in title case, these aren't classes. They're actual variables. So they look like classes, but
they're actual variables. But again, they're in title case, because they're constant. So I define
all the names of my routes up here, I have the home route, which is just slash, and the location,
detail route. Now, when you pass the slash route to flutter, it's already going to know,
hey, this is my first screen, I'm going to load. Great. So now let's go back. And now I can say,
push named, and then locations route. And then I'm going to show you how I can pass an argument
to that. So we're going to have to pass this location ID to this push named function. And
to pass an argument to it, there's an arguments parameter. So for push means we have arguments,
and all that arguments is a map, so a map type. And then we can define whatever we want here,
I can say ID, and then location ID. And our screen is actually going to use this, and I'll
show you in a minute how it's going to use it. So we're going to refer to it by name, like ID
and then the value location ID. And we're going to remember that we use this ID key to our map.
So let's continue on. So in app dot darts, here's what we're going to do, we're not going to use the
routes parameter here. So I'm going to remove that. Also, we don't really need initial route,
because we already have a route called slash. And that just loads First, we're going to have,
we're going to use a special parameter called on Generate route. And on Generate route is giving
us a dynamic list of routes. It's in the form of what's called a route factory. And route factories
is the fancy term, which is a basically a payload, that of data, it's a chunk of data that just says,
Hey, here are my routes. So let's create a pass it a function we're going to implement,
it's a private function. So starting with underscore called routes. And now we're
going to implement that here, because it's in our app dot Dart, it's on the highest level, it's
easiest to define that here. So it's gonna return a route factory. And I'll show you what that route
factory is at the end of the day, in a second, rather, um, and this function is going to return
some data. So it's going to return an actual function. So if you click into on Generate route,
that is a route factory. Let's click in a route factory. And route factory is actually a function
that takes in a bunch of settings, and returns a route of type dynamic. So I won't like drill into
this too much, let me implement that. And that will make a lot more sense. But what we have to
do at the end of the day is return a function. So a function with the parameter settings. So
we're going to use settings here. And I'll show you how we're going to use settings. So first,
we're going to get the arguments to our whatever route was tapped. So arguments. And settings has
this member called arguments. So we can use this settings for getting all kinds of information,
but arguments is one of them. And now we're going to create a variable called screen and screen is
the actual widget and the final screen that's going to be returned to us based on the name of
the route. So the name of the route that we have is defined as settings dot name. So if a user taps
on whatever they tap on, the given route that that they're wanting to reach is defined by the name,
which is going to be either slash or slash location detail. And what we're going to do is
use a new feature of Dart called switch and switch let's it's basically a glorified if and then else
if statement. And it has can have as many else ifs as you want, but it's just a more concise way
of saying if something and then else if something and then else if something else, right. So instead
of doing that, we can say switch, and we pass it the name of the route. And then I can say,
in this case, if it's the locations route, I'm going to do something custom, I'm going to say,
my screen that I want to return is a basically a new instance of the locations widget. And
then I'm going to say break because in a switch statement, it will go through every case until it
breaks or you return something. So next case is the location detail routes. And remember,
every case has to be ended by a colon, not a semicolon. That's really important and
most programming languages have Have a switch statement. So most of you, if you're familiar
with this, it, this is going to look like second nature to you. So for the location, detail route,
if I want to navigate to location detail route here, and that's defined by slash location detail,
I have to do something custom now. And I'm going to say location detail. And I'm going to use my
arguments map here. And I'm going to refer to it by the ID key. And that's what we defined here. So
locations, the arguments is a map, and there's a key in that map called ID, you should use single
quotes, by the way, by default, um, and then, and now it can instantiate with a custom arguments.
So now I have my screen, I have to import it real quick. Location, detail, location, detail,
grades, and now I can return it. So break. And now, the switch statement has this final case,
which is if none of the cases match, there's this default case, and you define it with just default
colon. And then by default, just running going to return null and do nothing. And then finally,
what I'm going to do is return what's called a material page route. And you we know that we
need to return this because a route factory is a function. And, yeah, I won't get into it too much
right now. But let me just say that you expect some material page route to be returned, right.
And material page route is a type of is basically a type of route. So going back to the basically
the route, factory type, material page route, basically, I didn't want to get too much into
it. But it is a type of route. So you can use any type of route. There's multiple types of Route,
but the most popular is a material page route. And then material page route takes in a builder,
and I wouldn't worry about builder, all it is is a fancy fancy way of being able to pass in something
dynamic, like an anonymous function here. So the syntax is a little weird, but basically, it's a
function that takes in a context. And you say, Okay, what, what am I returning, I'm returning
my screen widget. And that's it. So I know this looks a little weird. But basically, this is how
we define all like, all the routes in our app that needs to be dynamic. And what's nice about it is
that it's defined upfront in our app widget. So let's get this working. And then I'll show you how
it's going to work now. So on Generate route is routes. And before we get to working, I'm going to
quickly clean this up real quick because I want to use the I'm basically going to take my theme data
before this, before we get into work real quick. Let me just tidy this up because it looks pretty,
pretty, pretty ugly. I'm gonna say theme data, sorry for the tangent here. But I want to just
put this here, and I'll show you how easy it is to quickly get this tidy up. Great. So our main
screen is very clear on our app widget we have just on Generate route and our theme. And it's in
a method here so that it's nice and clean. Cool. So now that we've gone over that it was a little
tedious. But let's see if this will work. So let's check our code again, push named Okay, this should
work. Let's see if this works. Cool. Now, it's not loading the location Details screen and see it's
just like loading the location screen. So let's troubleshoot why this is happening. So in our
app dot Dart locations to those location details, that location, detail route, and to the name,
we're loading his seat, location, detail route. So we have to push named location detail routes,
and let's hot reload this. And when I click on something cool, it comes up. So we got it
working. I can go back and when I go back, it will pop it off the route. So there's no, you
don't need to implement this pop method. Like you don't need to manually write some code that says,
push this card that's on top of our deck off the stack. It'll just do it automatically. Because
we're using the material apps, material designs app bar widget. So app our widget automatically
will show a back button when the screen appears if it's not the home route, saying cool. So in our
next episode, we're going to actually implement that the beautiful location listing screen. But
this is just the nitty gritty kind of mechanism for navigation. Let me make sure I didn't miss
anything. Because the blog post basically explains in detail how this is all implemented. And it
gives you also links to the documentation. Let's see. Yeah, I guess that's it. Final app dot Dart
file. Cool. And I talked about going back and all that stuff like that. So there might be a better
way that you have for implementing routes that are dynamic that need dynamic parameters. But,
you know, feel free to reach out if you have a better way of doing this. But for now,
and how flutter is implemented. This is pretty much the most clear cut way of doing
that. Everything's defined up front in app dot Dart. So thanks for watching and yeah,