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.