ANDREW BROGDON: Hey, everybody.
I'm Andrew from the Flutter team,
and in the next few minutes, I'm going
to show you how using Flutter's Material Design widgets
can help you quickly break down a design
and turn it into real code that runs on both iOS and Android.
Google recently released a bunch of new stuff
for the Material Design system to help
app developers build beautiful, usable experiences fast.
With that came a ton of open-source code
that developers can use to implement those experiences.
There are native libraries for iOS and Android,
web components, and for Flutter, a whole bunch of widgets.
Expanding panels, buttons, implicit animations,
all kinds of stuff that you can use to quickly build
your own native apps.
How does that affect you?
Well, imagine you're an engineer and your company's
lead designer comes to you and says,
hey, you know how we were looking for a project
to get started with Flutter?
Turns out the animal shelter down the road could use an app,
so I mocked up a kitten adoption catalog.
How quickly can you get these two designs
turned into something we can actually
see on Android and iOS?
Well, no problem.
The first place to head is Flutter's Material Components
gallery.
Here you can find the widgets that'll
be the building blocks of your interface.
There's Scaffold, for instance, which
provides a visual framework for your app
with room for drawers and floating action buttons
and menus.
There are also dialogs, alerts, input elements for capturing
data, and a lot more.
With those widgets in your tool belt,
you can begin thinking of the design
in terms of how it's actually going to be constructed.
The first screen becomes a scaffold with a list view,
and the second becomes a simple dialog
with a networked image, some text widgets, and a couple
buttons.
A lot of times, this is when you, the engineer,
would have to go write up a design doc
and show what your plan is and then haggle over
the details with the designer.
But Flutter's built to make app coding quick,
and in less time than it would probably
take you to produce that doc, you can just knock out the code
and have something real for people to look at.
So let's do it.
Let's get into an editor and start putting components
together.
OK, here we are in a very basic Flutter app,
about 20 lines of Dart code.
First step to mocking up is mock data.
So I'm going to use the magic of cut
and paste to add a class to hold my kitten data.
There's nothing fancy here, just four properties-- name,
age, description, and a URL for a kitten pic.
And now for some data.
Because iOS simulators and Android emulators
use different addresses to represent
the actual machine they're running on,
I'm going to add a global string for it.
And then I'll create a list of kitten objects
with image URLs that work on either platform.
There we go.
Four cats, easy peasy.
For the images themselves, I've got them in a folder,
and I'm just going to run Python's simple HTTP server.
So for all my app knows, these images
could be coming from any server on the net.
OK, with the data in place, it's time
to start building out the UI.
Here's my home page, which is just an empty container
right now.
And I'm going to replace it with a scaffold, which
provides some visual structure for everything else.
And it has an AppBar property I can use
to put a title bar in my app.
Available cats-- let's do kittens.
All right, so when I save this and do a hot reload,
I get this.
It's a start, and it's running on both an iOS simulator
and Android.
If you haven't seen hot reload in action,
Flutter can quickly deploy code changes to your app
while it's still running.
So I'm going to be making small, incremental changes
and then flipping back to these instances of the app a lot
over the next few minutes.
All right, let's add a body to the scaffold.
This is where the list view comes in.
I'll use the name to build a constructor, which
takes three parameters.
First is itemCount, which is just the length of my list.
There we go.
Then comes itemExtent, the height of each item.
And I'll just go with 60.
And last is the Builder.
This is the method that's responsible for building
the widgets that'll display each item.
And I'm just going to make up a name
and give it a function, here.
I'll define that method up here.
It returns a widget and takes a BuildContext.
And that BuildContext just represents
a spot in the hierarchy where these widgets will be placed,
and it takes the index of the item as well.
And let's start with just a text widget for the kitten's name.
There we go.
And hot reload.
All right, we got some names, but they're pretty small.
I can use a text style to fix that, though.
One of the material components for Flutter is theme.
Every app starts with a default theme,
and I'll be customizing it later.
This code gets a reference to the theme object
for the correct context and then styles the text widget
to match the headline font.
This something of context pattern, by the way,
pops up a lot in Flutter.
This is how you get the Navigator to push routes,
for example.
And you could even get a reference
to the containing scaffold that way.
All right, hot reload.
And we got big names.
They're still locked on the left edge, though,
so I'll wrap the text widgets in a container
and set some padding, here.
I think 16 should do it.
There we go, Container.
And I'll set the padding property with a constant of 16.
Once I've got that done, I just need to add an alignment here.
There we go.
And I'll use centerLeft.
That gives me vertical centering and left alignment.
All right, another hot reload, and there we go.
One last thing to do.
Our app is blue, but the design was purple.
So let me scroll up.
MaterialApp, which is the widget that represents my entire app,
has an optional theme parameter in its constructor.
I can give it some theme data that'll
be merged into that default theme.
So I'll set the primary swatch to purple.
There we go.
And one more hot reload, and I've got purple.
My first design is implemented.
All right, so that's one screen down.
Now let's get the rest of the design working.
I'm going to launch a simple dialog with some text, image,
and button widgets that display details
for an individual kitten.
That's probably not a sentence you hear every day.
Let's get to it.
First order of business, I need to launch
the dialog in response to a tap, so I need a GestureDetector.
There we go.
I can use its onTap property to get myself wired up.
So no parameters needed.
I'm just going to call showDialog,
which is a top-level Flutter method that
takes a context and a builder function that's
responsible for creating the widgets that
compose the dialog.
Just like with the ListView.builder,
I'm going to give it a name, dialogBuilder.
And then I'm going to define that function up here.
It returns a widget, and it accepts
a build context and a kitten.
I'm just going to have it return a container
to start so we can see what this dialog actually looks like.
There we go.
I'll give it a width and a height, say 80 of each.
It's just going to be a big, black box.
OK, hot reload, and let me tap on Mittens, here.
Both sides.
And I got empty dialogs, cool.
All right, so let's replace the container with something real.
I'll start with a kitten image.
I could use the Image class--
there we go-- which has a named constructor
for network-loaded images.
And I'm just going to give it the URL, which comes straight
out of that mock object.
And I'll give it a fit of fill.
There we go.
So it's a full-bleed display.
Format that up and hot reload.
Hey, Mittens the Majestic, all right.
And let me try one of the other cats.
Steve, here, he's pretty cool.
Excellent.
OK, so that image is full-bleed, but my text widgets and button
should have some padding around them.
So I'll use a Padding widget.
There we go.
And another 16.
And inside, I'm going to use a Column widget, which
can display the instances of text vertically.
There we go.
Format that up and hot reload, and so there's
my padded empty column at the bottom.
And speaking of padding, that space above the image
is still there, and I need to take it out.
That's not part of the design.
Fortunately, I can set the content padding
on the dialog itself to 0.
There's actually a constant for it.
So EdgeInsets.zero.
And there we go.
OK, time for some text widgets.
There's the name, the age, and description.
There's one, get another one for age in here,
and then description.
Now, age is an integer, so I'll use Dart's string interpolation
to convert that to a nice string.
Hot reload, and there's my text.
But it is unstyled and unaligned,
so we got some more work to do.
Alignment is easy.
Rows and columns have an alignment for their CrossAxis,
a property for that.
The main axis for a column, of course,
is vertical, so cross-axis alignment controls
how things are set on the horizontal axis.
I've got this set to Stretch.
So reload, and everything's there.
Cool.
So I need some sizes on these, and that means a theme object.
I'm going to use it a few times in here,
so I'm actually going to cache a local copy up at the top.
There we go.
Now I can come down, and let's say display1
for this one, which is a really big font size.
There we go.
Scroll down.
And hot reload.
There's Steve, OK.
And I'm going to knock out the rest of these pretty quick.
I'll use subhead for the age.
That's a good one.
And the copyWith method allows me
to modify the theme instance, sort of
like I did with the purple color earlier.
So I'm going to make that italic.
And I'm also going to use a widget called SizedBox, here,
to just block out some space between the age
and the description.
With that done, I can set the description
to use the style for body text.
There we go, body1.
Get that formatted up.
All right, and hot reload.
There we go.
All right, now I just need some buttons.
First I'll use a Wrap widget, which is like a row
but will wrap its children if they extend too far.
There we go.
Then I can use a FlatButton for the first choice, which is
sort of like the Cancel button.
Let me get that in there.
And I'll put I'm allergic, because why else would you
not want a kitten in your life?
And for the default action, I'll use a RaisedButton.
And that one's going to say Adopt.
And you'll note, I'm just giving these empty methods
for their onPress properties.
That way they're enabled, but they're not
going to actually do anything.
OK, cool, so I've got some buttons.
They're not aligned right, though, and the colors are off.
Alignment's easy.
I can fix that by putting the Wrap widget in an Align widget
and then setting its alignment property to centerRight.
And I'm also going to use another SizedBox to get
some space in between the buttons and the description
text.
And while I'm in here, let me actually
use the Navigator to dismiss the dialog when
that first button is clicked, the I'm Allergic button.
This is another one of those something of context methods,
like I mentioned before.
There we go.
All right, my buttons are in the right spot,
and clicking dismisses the dialog properly.
Let's get Scooter up here.
All right, at this point, I just need
to change the styling of my buttons
and I'm pretty much done.
So I'll come back up to the theme for my app,
and I'll set the button text theme to primary,
which will be white text.
Here we go.
And then I can set the buttonColor
itself to purple as well.
All right, one last hot reload gets
me a finished implementation.
I've got all the elements in place,
and everything is styled just like it
should be to match the design.
All right, after having spent just a short time coding,
you can now go back to that designer,
hand them builds of the app for Android and iOS,
and get feedback based on actual code running on device.
That's one of the goals that Flutter's
designed for-- getting from idea to app as quickly as possible.
That's it for today, but if you'd
like to learn more about Flutter,
we've got links to guides, sample apps,
and a bunch of other resources in the description
for this video.
So check those out, and head to Flutter.io to get started.