[MUSIC PLAYING] BRIAN JAMES: Hi, I'm Brian,
a User Experience Engineer on the Flutter UX team. I combined my background
in design and code to help build
Flutter and explore its creative possibilities. LEIGHA JARRETT: And
I'm Leigha, a Product Manager for Flutter focusing on
design and the Apple ecosystem. Now, you probably already
knew about Flutter's speed and productivity. But today, we're going to
talk about creativity and why Flutter is such a great
choice for bringing your unique, ambitious
designs to life. To show you what
we mean, we'll take on the role of creative
coders, working on a fictional
font-themed puzzle app with complex animations
and custom special effects. Now, this won't be a
tutorial, but we'll show you examples
of how Flutter's easy-to-use components and
its powerful graphics features can be combined to
create a unique design. We'll start with simple
widgets and custom styling and build up to complex
topics like animations, custom graphics drawings, platform
adaptivity, and even variable fonts and
shader support. So whether you're a Flutter
newcomer or a seasoned pro, we think you'll find some
new ideas to explore. Let's start by looking
at our design mockup-- in this case, a Figma
prototype for our new game. The concept is that
the player just got hired at a font
company, and their first job is to publish a new font file. But when they click
the OK button too hard, it scrambled the font. So now, they're seeing all
these letters are kind of wonky, and their job is to
put them back together by solving the puzzles. OK, sounds fun. So now, let's get started
writing some code. BRIAN JAMES: Let's start simple. The first screen is
pretty straightforward. We've got a couple
of text blocks with different
fonts and a button. In Flutter, everything
is made of composable, reusable UI elements
called widgets, and that makes building
app screens really easy. So in our case, we might want a
few widgets for the text blocks and one more widget
for the button. For those of you just
getting into Flutter, be sure to check out the amazing
documentation that the Flutter team has available
at docs.flutter.dev, specifically, the
widget catalog. Right now, we want
the Text category. And here, we have
the Text widget. There are even examples
of how to use it. LEIGHA JARRETT: Awesome. I'll go ahead and add
this into our app code. First, I'll create
a new widget to hold the contents of our first page. And inside this widget, I'll
add the Text widget that says our little welcome bit. I'll also create a
few other text widgets to hold our alphabet strings. Oh, and one other point
for new Flutter devs-- widgets aren't
just for components like texts or buttons. They're also used to
control the layout. Basically, everything
is a widget. So watch how I can
use a Column layout widget to stack
the different Text widgets on top of each other. And I can use the Padding widget
to specify the amount of space surrounding the Text blocks. Next, we need to
create our button. So Flutter lets
you easily create different styles of buttons to
match the design of your app. These ready-made buttons
look great out of the box, but if the style isn't
quite what you had in mind, you can use it as a starting
point and customize its look. You're probably already
familiar with Material Design, the design system
used here at Google, and Flutter has
several button options that fit into that system. In our case, let's
use an ElevatedButton. We can add ElevatedButton as
a child of our Column widget. And now we can
see it in our app. I think we're off to a good
start, but the font and colors, they don't really match what
we originally had in mind. To control app-wide settings
like different textiles, color schemes, or styles for
individual classes, we can create a theme. An app theme is kind
of like a style sheet. So in Flutter, you create
a theme by using ThemeData. And to propagate the settings to
all the widgets within the app, we can use ThemeData as an
input to the MaterialApp class. BRIAN JAMES: Before
we specify our fonts, we'll need to bundle the
font files into our app. I can just drag and drop
them into the project folder and then specify them
in the assets section of the pubspec file,
which contains metadata about the Flutter project. Or I can use the Flutter
google_fonts package which lets me bypass this step. It downloads
whatever Google font I want on the fly, which is
especially useful to try out several fonts. LEIGHA JARRETT:
Great, so now we can use those fonts in our ThemeData
by creating different text styles. Here, we can use a TextTheme,
and within it, we'll create different text
styles that correspond with the different font families
or sizes used in our app. To specify what style we
want our Text widget to use, we can refer to it in
the style parameter. Our text is looking good,
so now on to the button. We can control the color
scheme for our entire app, or we can use theme classes
that are specific to the widget classes that we're using. In this case, we'll use
the ElevatedButton theme and specify the
background color. And now we can see the screen is
looking just like our designs. BRIAN JAMES: These
customized themes give us a lot of design options,
but it doesn't stop there. With Flutter, we can easily
make fully custom UI components that don't look like
conventional buttons or switches or sliders. Just to scratch the surface
of the possibilities, let's say we wanted to make
something a little quirky, like a button with two
sharp corners and two rounded corners. It's not as hard
as you might think. Let's start with a
Container widget, which is a very generic
widget that just gives us a box on the screen. And we can control
its appearance with a BoxDecoration. LEIGHA JARRETT: Now, I
can use that in a brand new widget class
called MyCoolButton, which will return a container
with a BoxDecoration. Within BoxDecoration, we
can change the BorderRadius for two of the corners
to make them curved. Plus, we can use
the backgroundColor that we defined in our
button theme earlier. So let's move on to the next
page of the app, the settings. Now I know a settings page
doesn't sound very exciting, but stay with us, because
we're about to show you a great trick. We'll make a simple
settings page to turn the sound on or off. And for this, I'll just go
ahead and use the Switch widget from the material library
that we tested before. But now that I'm
taking a closer look, this looks great
for Android devices, but native switches on
iOS look a bit different. Thankfully, Flutter also
has the Cupertino library, which includes a set of
widgets that use Apple's Human Interface Guidelines. Here, we can see this looks
more familiar to iOS users. And even better, I can use
the .adaptive name constructor to create a Switch widget that
will automatically alternate between Material and Cupertino
depending on what platform the game is played on. So Flutter can actually
sense which operating system the app is running on and
change the designs accordingly. BRIAN JAMES: Flutter also does
a bunch of platform adaptations automatically behind the
scenes, really detailed things like scrolling speed, what
happens when you scroll to the bottom of a page,
and haptic feedback to help your apps feel
natural, whatever platform they're used on. LEIGHA JARRETT:
That's so important to make cross-platform apps
easy to use for the consumer. Anyways, let's keep
chugging along. So before we get
to the game itself, let's try and tackle the
page that a user sees when they finish the puzzle. First, we have a
Congratulations textbox. And then we have a
line chart showing the user how many moves it took
to solve the puzzle each time they played. It's kind of tracking
their score over time. We already know about
the Text widget, so let's focus on
that line chart. We want to be able to draw a
line between different points, and the placement
of those points will depend on the number of
games that the user has played and how many times it
took for them to win. So far, we've seen how to make
custom boxes and box shapes, but I don't think that's
going to work here. If we want to draw custom
shapes, curves, or lines, we can use the
CustomPaint widget. It works a lot like a pen
tool in a digital illustration app, where we draw a path
between various points. But since we're creating
these points programmatically, then we can respond to
different inputs from our app, like the player stats
that we'll be using here. First, we'll use the
CustomPaint widget, and then we'll need
to create a custom class to use as the painter. Our LineChartPainter will
specify the stroke color and width that we'll use. And in our case, we'll create
two paints, one for the axis and one for the
data on the chart. We'll also create two paths. For the axis path, I can
just draw a line vertically to the canvas height and
horizontally to the canvas width. Now, for the data, I can
loop through each point and draw a line to
that coordinate. Then we simply feed in
the paint and path object to draw the path on the canvas. And even though we're just
drawing a few straight lines for this example,
CustomPaint lets you draw really complex
shapes with combinations of lines, bezier curves, and
multiple closed or open paths. It gives you so
many possibilities, and if you're looking
for inspiration, check out gskinner's vignettes. BRIAN JAMES: At
this point, we've seen some standard widgets
like Text and Container, some widgets that follow
established design systems like Material Design
and Apple's Human Interface Guidelines, and we've built
totally custom widgets to match our own designs. Now let's bring those widgets
to life with some animations. Motion design is one of the
most interesting and expressive types of design. It's also a great bridge
between classic visual design and interface or
interaction design. Flutter gives you a range
of tools for animations, so let's start with
the simplest ones. There's a collection
of animated widgets ready for motion out of the
box with almost no extra code. These are called
implicit animations, and they're a convenient way
to implement simple motion designs in your app. Just like regular
widgets, we have a variety of parameters we can use to
customize how a widget looks, like the color of this animated
container, which is set to red. With implicitly animated
widgets like AnimatedContainer, when a parameter like
this gets changed, the widget automatically
animates from the old setting to the new one. Let's apply this to the
Congratulations text on our end screen. We'll make the text
animate up in size and get darker in
color just for fun. Fortunately, there's one of
these implicitly animated widgets for just
such an occasion, AnimatedDefaultTextStyle. I've wrapped my Text widget in
the AnimatedDefaultTextStyle and use the named parameters
to control the visuals, like duration, which
sets the animation's speed, and fontSize, and color
to set the size and color, using two variables. Higher up, we've
set those variables to our start settings, small
size and transparent color. Animations can be kicked off by
basically any event you want, like tapping a button
or new data coming in. In this case, let's
use a timer, like this. It has a half-second
delay, and then it changes the size
and color variables that we set up before. So the text will hold for just
a moment on the start settings, then animate to this new
size and color, like this. We can even customize the
animation timing or curve. The default curve
is called linear, and it goes straight from
A to B, like we just saw. But we can also
manually set a curve like this, with a
bunch of great options like easeOut for
a subtle slowdown at the end, or even bounceOut. And just like that, we have an
animation for our end screen. LEIGHA JARRETT: Now,
we're not expecting you to memorize all of these,
but do remember to check out Flutter's great reference
docs and the official YouTube channel with
bite-sized tutorials like "Widget of the
Week," as well as longer podcast-style content. If you're new to
Flutter, we highly recommend the "Learning
to Fly" series. So using the
ready-made implicitly animated widgets is really
convenient and powerful, but what if there isn't an
animated widget for what we want to do or we have a more
complicated animation in mind? BRIAN JAMES: For
example, let's say we want to animate the
line chart we made earlier so that the line draws
across the screen rather than just popping on. That's very customized,
so we'll need to create our own
animation from scratch. Flutter calls these
explicit animations. Explicit animations use
animation controllers, which, as you've
probably guessed, let us control the animations. There are a few ways we can
use animation controllers. One of the most common
involves tween objects. That's short for "in between,"
like animating between a start and an endpoint. This next part will
get a bit complex, so we're going to
leave out some details and just focus on the most
crucial parts of the code. Having set up the
AnimationController, we'll create a tween
sequence to animate from one point on the graph to another. These points are called
offsets in the code. Next, we add a listener. For every frame
of the animation, the listener updates
the dx and dy variables, which control how much of the
graph we draw in each frame. Those variables get plugged
into the custom painter we set up before like this. And there we have it. Our chart draws itself with a
custom animation we created. LEIGHA JARRETT: So far, we've
been building up the intro and outro pages of our game. Now let's start getting
into the game itself. We've already dabbled with
some subtle animations, but let's go big this time. What if we take the letters
surrounding the puzzle pieces and distort them? This kind of effect is made
possible by variable fonts. They give designers deep
control over text styling. So with variable
fonts, we can control not just the size
and the boldness, but any other settings that
the font creator allows us to. This could include things
like the width of the letters, the relative size
of different parts, all kinds of really
detailed settings. BRIAN JAMES: Flutter lets
you use variable fonts with the TextStyle class,
which we talked about earlier. We access individual
variable font parameters with the FontVariation class. And you can add and combine
as many of the font variations as the font file itself
supports by plugging them into the TextStyle's
fontVariations field. Variable fonts can be
great for practical things like increasing legibility,
but they can also provide a bit of visual
flair, especially when they're combined with animation. I think animating
between extreme settings will really add to the glitchy
concept of the game's story, so let's give it a try. Let's say we want to animate
a variable font from a very lightweight, like 100, to a
very bold weight, like 1,000. This is a custom
explicit animation, so we'll use an
AnimationController and a Tween again, which we're
already familiar with. You can see we're animating
the Tween from 100 to 1,000. Remember that we've named this
Tween variable "animation" because we'll use it again. One new point in the code is the
curved animation we've set up, which is one way to attach
a timing curve like bounce or ease to an
explicit animation. Here, we're using
ease in and out. We connect that Tween
as animation.value with the FontVariation
for weight, like this. And remember that the
FontVariation lives inside a TextStyle, like this. And if we do this on a bunch
of letters at different speeds, we get this, exactly
what we wanted. And we're not limited to
animating the font's boldness, like we see on the left. In the middle, we see our
variable font changing widths and even things like ascenders
and descenders, how high and how low the tops and the
bottoms of the letters extend. This was kind of a
weird idea, but I think it's working nicely. LEIGHA JARRETT: The variable
font animations are definitely creating a cool
distorted effect, but let's push it even further. I think we could get a really
glitchy, eye-catching feel with some custom shaders. Shaders are a pretty
advanced topic, but if you want to get really
into graphics programming, Flutter lets you create
custom fragment shaders. Shaders are programs written
in a specialized language separate from Flutter and Dart. They run directly on your
computer's GPU, or Graphics Processing Unit,
and they can create all kinds of visual effects. Flutter lets you
code your own shaders and plug them into
your app, so you can apply the effect to one
widget or the entire screen. And because shaders
run on the GPU, they take work off
of the CPU, which helps you keep your app
running at a high frame rate. BRIAN JAMES: We don't have
time for a full shader tutorial today, and honestly,
I'm not a shader expert by any means. But just to give a quick
idea, this code snippet, written in GL Shader
Language, will stretch the pixels of
whatever it's applied to and create a wavy effect. And we can use regular animation
controllers to make it move. Like before, we're just
showing key parts of the code. But here, we're connecting
an animation value into the fragmentShader object
we just coded with GLSL, and we're using it
in a custom painter. That's one way to
apply this shader and make the effect shift over
time, creating an animation. And there it goes. The shader effect
is now animating, and we're controlling
the animation through regular Flutter code. Again, shaders are a
fairly advanced topic, but if you're up
for a challenge, try experimenting with
them in your next app. LEIGHA JARRETT: So we
covered a lot of ground today, and don't worry if
you didn't catch everything. Our main goal was to
give you a few ideas to explore as you make your
own amazing designs in Flutter. If you're new to Flutter and
not sure what to do next, you might like to start with
a no-installation web-based experience at
DartPad.dev, where you can find sample apps
to tinker with or even write your own simple
app from scratch. Thanks for watching,
and we can't wait to see what you create next. [MUSIC PLAYING]