MARTIN AGUINIS: Hi, everyone.
I'm Martin from the Flutter team.
Today, I'm going to show you how Flutter's widget composition
can help you quickly build out a beautiful interface
for your applications.
If you haven't tried Flutter yet,
it's Google's new mobile UI SDK that
can help you quickly build native iOS and Android
apps from a single codebase.
Widgets are the building block of any app built with Flutter,
and their functionality spans from providing
a framework for your entire app, like the scaffold widget,
to accepting input, like text field does,
or even animating an ink splash.
Every widget has its own particular purpose.
And you, the developer, build your app through composition,
putting individual widgets together
until they add up to a great interface.
Let me give you an example.
Say you're an engineer at a shop that
builds mobile apps for other companies.
And one day, your biggest client comes to the office and says,
we have to talk about an action button on our shopping app.
The look just isn't working.
We need something that really feels like our brand.
As a Flutter developer, you can say, no problem.
Have a seat and I'll pull up the code.
All right.
So here's your client's app.
And if we zoom in, you can see this default
looking floating action button.
There's nothing wrong with the basics,
but you can see why the client might want
something a little more custom.
And here's the code that produces the UI you just saw.
It's written in the Dart programming language,
which is what Flutter uses.
There is the MyHomePage class up at the top.
And here's the bit we're interested in,
the floating action button.
Let's create a new file and define a new widget
to use instead of the default. We'll call it FancyButton.
There we go.
Let's import a couple of the basic Flutter packages.
There is the foundation and the material package that's
got a ton of widgets in it.
And I'll define FancyButton as an extension
of stateless widget.
I'm going to skip over the details
of stateless widget for now.
The important thing, as far as we're concerned,
is that stateless widgets don't have mutable properties
or a state that can change.
You just construct one and it's good to go.
Speaking of properties, let's give the button
a callback for when it's pressed.
And we'll need a constructor to inject the callback.
So let me add that.
If you're new to Dart, you may not
have seen this in a constructor before.
It just means that the constructor
should have a parameter that matches the property
and handles the assignment for you.
I can also put braces around the parameter
to make it an optional named parameter.
You'll see how this works when this gets invoked.
And use the required annotation to make
sure it's always passed in.
And there's one method I need to implement here, which is build.
This is call by Flutter, and it's basically
a way of asking your widget, hey, who are your children?
What widgets are below you in the hierarchy?
I've just got a placeholder null in here
so that I can go back to my home page.
Let's get the new file imported, and then I'll
come down here and replace the default button with my widget.
You can see the name parameter for onPressed.
I'll give it the same method that the other button
was firing.
OK.
Let's get back to FancyButton and the build method.
This is where the composition happens.
I'm going to start putting child widgets together
to define how this widget looks and performs.
Let's start with some text.
Maybe the client wants the button to say PURCHASE.
Now I'm going to build this.
And since this is the first build,
it's going to take a few seconds.
Once the app is up and running, we
can use hot reload to cut the refresh time
to less than a second.
But more on that later.
In the meantime, there's the interface.
And there's the word PURCHASE in the corner.
So we've got something going.
OK.
So we need this widget to do more than just
print black text.
And in Flutter, you can add a capability
by putting widgets together.
So let's wrap the text with a basic button called
raw material button.
The text widget now becomes its child,
and I'll add a comment at the end
here so that the auto formatter makes it look nice and pretty.
Raw material button has a few properties.
So let's start with color.
I'll fill it with deep orange and use regular orange
for the ink splash.
Now, let's save and do a hot reload.
That's going to update the app's code
without restarting the app.
And there is my updated button in about 400 milliseconds.
Now, I'm tapping on the button here.
And as you can see, there's no splash,
which is because we haven't given this raw material
button anything to do.
So let's give it the fancy buttons onPressed call back
and a hot reload later.
I get a nice splash.
What's next?
Say the client wants a rounded button.
I can do that by giving mine a stadium border as its shape.
And I can call that constructor with a const keyword here.
That's always nice.
In fact, it reminds me, I don't need the new
on raw material button.
The new keyword is optional in Dart 2,
so I can pop it right out.
OK.
Let's hot reload and see the new shape.
Boom, rounded edges.
This quick cycle of making a change,
see the result, making the change,
see the result is something Flutter was designed,
from the start, to provide.
All right.
What else can we do?
Let's give the text a little more pop
by changing it to white.
There is a style property for text widgets
that can help me with that.
We can give it a textile object with the color set to white.
OK.
I've got some white text.
What about more padding?
Sounds like a fun job for the padding widget.
I'll wrap the text in an instance of padding and I'll
make it symmetrical, 8 for vertical and 20 for horizontal,
and hot reload.
There's the padding.
What else might the client want?
How about an icon?
A lot of buttons have icons.
The problem here is that padding takes a single child.
But we want it to have two--
text and an icon--
so we need a container.
Flutter has a number of them and they
are, as you probably guessed, also widgets.
We can use a row widget to display the icon and text
widgets next to each other horizontally.
Instead of a child property, row has a property called children,
which takes a list of widgets.
Let me finish up by getting the icon in there.
All right.
And now to hot reload again.
And whoa, that's not right.
Looks like I forgot to set the main axis size for the row.
The main axis for row is horizontal.
So this code tells the row widget
to use the smallest amount of space it can.
All right.
Let's hot reload again.
There we go.
This is another nice thing about hot reload.
I just messed up the UI by forgetting to set a property
and I was still able to go back, add a fix,
and keep going without a restart.
Next, how about a little space between the icon and text?
There is a great widget for that called SizeBox.
You can give it a dimension or two
and it will take up some space.
And you know what?
All three children of the row are constants.
So let's just move that const up to the list itself.
There we go.
All right.
Hot reload.
And there's SizeBox at work.
Not bad.
At this point, we've composed a completely new button
with six widgets, each of them handling
its own particular responsibilities
and combining to give the client a button that's
vibrant and unique.
So far, we've mostly used widgets
to control basic presentation details.
But they can do a lot more.
For example, say you're displaying an image
and you'd like to know when the user taps on it.
Just wrap the image in a GestureDetector widget.
There are properties for taps, long presses, drags, and more.
Just like the graphics-focused widgets you've seen,
GestureDetector handles it's one particular area
of responsibility and that's it.
All right.
Let's get back to the app and put some more widgets to work.
OK.
We're back with a button.
Let's say the client's so impressed with what
you've done that they really want to push the envelope.
How about a vertical floating action button?
No problem.
There is a widget for rotating other widgets.
It's called RotatedBox and we can give it 3/4 turns
and get this.
It's vertical and everything.
But maybe just because you can do a thing
doesn't mean you should.
So let's pack it out with the Remove widget.
You can use RotatedBox on a lot of stuff, though.
Say the client preferred the little compass icon
to point the other way.
No problem.
There it is, leaning back instead of forward.
By the way, so far I've been composing
with widgets that are part of core Flutter,
but it works the same with widgets built from scratch.
For example, let me drop some code in here real quick.
Say I had another widget that I'd already built
called PulseAnimator, with a child property of its own,
and its job was to apply a pulsing animation to the child.
You can use the same composition strategy with it
that you do with the stock widgets.
Here, I'll add it to the hierarchy and make this text
its child.
And when I hot reload, there is the animation.
So there you go.
That's eight widgets in combination
to make a great button and a happy client.
So now we've got an updated app and a happy client, all thanks
to widget composition.
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 video description below.
So check those out and head to Flutter.io
to get started today.