[MUSIC PLAYING] LIAM SPRADLIN: Hi, I'm
Liam, an interface designer and senior design advocate
on Material design. Today, we're going
to quickly walk through what it might be like
to build a new app with Flutter and Material 3 starting from
concept and some existing brand parameters. We'll be using our
sample app, Pesto. It's an app that has several
different user journeys that can take place across
different device types, input modalities, and contexts. For example, you might enter
and manage your recipes on a computer screen, browse
for inspiration on a tablet, and carry out the recipe
on an ambient device. RODY DAVIS: And I'm
Rody, a senior developer advocate at Google. This is a preview of what
we're trying to build. When you run the code,
it may look different. But feel free to take it as
a starting point, hack on it, and try to make
Pesto for Wear OS. Flutter may not
support the TV context. But you can still prototype
how the UI will look and behave and test it on a desktop
or web application just with a simple
platform override. LIAM SPRADLIN: From a
designer's perspective, we build layouts and
experiences for apps, like Pesto, with a ton
of contextual information in mind, meaning that our
intention for the experience, how it works, how it feels,
the character of the design is embedded deeply into the
artifacts of our work often without explicit markers
for the other people who we're working with
to bring it to life-- things, like
layouts, which often rely on structures that
aren't immediately visible or aren't visible at all. And when you add responsive
behaviors into the mix, it becomes really important
to communicate intent with developers. Similarly, navigation patterns
require nuanced choices about componentry and behaviors. And brand customization
carries important parameters that may not be
obvious to anyone who's not already familiar with
existing guidance or values. [MUSIC PLAYING] RODY DAVIS: In this
talk, we'll keep track of the key elements
in our example app and talk about how
Flutter and Material 3 make it easier to convey and
preserve our design intent. When it comes to
translating a design, we as developers often
put parts of our UI into components and share
common behaviors and elements. This works for most use cases. But there are definitely
times where something needs to exist for
a single screen and is not meant to
be component-sized. Hopefully, this
talk will teach you that is perfectly acceptable
to build your design on top of custom components. And they are still backed by
Material theming and tokens. These widgets pair nicely
with the beautiful Material 3 widgets and can be heavily
customized to your needs. When working with designs and
translating them into code, one of the first things you'll
run into is the 12-column grid. This has been present in
designs for a very long time and has been especially used
in the web world with CSS grid. In Flutter, layouts are
based on the Flexbox model. And we are used to
rows, columns, stacks, and flexible widgets,
which we will use to compose the UI
based on size constraints. But Flutter has
quite a few widgets that help with
adaptive components such as fractional size box,
layout builder, fitted box, and slivers. There are a few packages
that can help us create the grid easier in Flutter. But know that there are multiple
ways to solve this problem and will depend on the
specific application. After you have a working
version of your app, and you start to adapt
it to other platforms, you may run into a problem of
having too much white space or not enough and really not
knowing what to do with it. Since Flutter supports
six platforms, the variation of inputs
and aspect ratios can change drastically. For example, mobile devices
with a keyboard and no mouse, laptop devices with a touch
screen or detachable keyboards, and a keyboard and mouse
connected to a mobile phone via Bluetooth. We need to take all this into
account when creating our UI and know when to remove
and add information where it makes sense. Mobile experiences
can be optimized for getting the most
important information quickly. And desktop can be optimized
for data manipulation. When there's a lot
of white space, consider canonical layouts where
we can move data horizontally, like on a foldable
display or tablet in landscape orientation. When building
applications in Flutter, it is common to start before
the API is even built. And we can use that to
prototype and show it off. Because the data will
be fake, and there's going to be gaps that we're
going to be filling in, it's important to cover
the cases you may not even think about. There are many testing
packages out there that will make this easier. Make sure to test for
long strings of text and to see where you
need to set overflow in ways of expanding the text. It could be tempting to set the
text with a tech scale factor to prevent the size
from breaking on the UI. But accessibility is important. And the app should work
with large font sizes. Make sure to check for relative
positions such as start and end instead of left and
right because this will be important for languages
where the app is running and right to left. Also, make sure to
check for edge cases where a string is
empty but not null and contains characters
you may not be expecting. If you need to render
HTML or markdown, make sure to check out
the markdown package. LIAM SPRADLIN: We'll
start designing Pesto with the layout, the
foundation for our app on top of which we'll place component's
information and actions. We, of course, want to start
from an adaptive structure since we already know that our
app will be run and experienced across different
devices and contexts. Building an adaptive
behaviors from the start has a lot of benefits. First, the app is more
usable because users recognize patterns and
experiences across surfaces. And adaptive layouts
can provide access to more and different
information that better suits the user's context. Apps that are designed to
work well on each platform are also perceived better. Consider what your
first impression may be if you open an app on your
tablet to find it letterbox or stretch it out. Finally, optimizing your
app for multiple devices makes it available
to a wider audience, meaning that more people
can enjoy what you've built. The first step in preparing your
app is conceptualizing a grid. If you're building for
the web, the notion of a column grid
and its importance may already be familiar to you. But if not, you may be
wondering, why use columns? Columns are a great way to
conceptualize interface designs for a few reasons. First, they create a
convenient structure for aligning elements
to your layout. Column grids have been in use
in print and graphic design for a long time. And that's because they
create the structure that print layouts
need, helping make printed Materials ergonomic
and maximally readable. Printers have used and
refined these layouts to help their users get the
most out of the material. And we can use them to the
same ends and interface design. In Material design, we also
think about layout regions. Most layouts have
navigation and body regions to divide overarching app
functions from the content that a user may be consuming. How does the layout
grid manifest in Pesto? The main screen is
a simple collection of recipes that can be
filtered with chips at the top. This makes the grid
pretty straightforward. On mobile, it's a
standard four columns. And each item is full width
spanning all four columns. On larger screens, we use
the recommended 12 columns in the content area
plus a navigation rail that makes navigation
easier to see and reach. The recipe cards
span six columns each on the larger screen size
in a staggered grid that reveals more information and
adds visual interest to make better use of the form factor. RODY DAVIS: In design,
grids are everywhere. But you may not be using them
in your current applications. To build with a
12-column grid, you can use a few
different techniques. And there are even some packages
that make this easier to use. You may be thinking, why not
just use rows and columns? But while that will let you
build any one type of UI, it really starts
to break down when you build responsive
layouts that need to flex a certain way. Another reason you may
want to use the grid is for having a lot of elements
aligned to specific grid lines. It can be subtle. But when you notice
something is not aligned, it really stands out. It's not just about how but why. We can create a
12-column grid in Flutter with a package called
Flutter and layout grid. This works like CSS
grids back on the web. And you will define grid
areas, column and row widths. And children will be
placed on the grid instead of the layout being inflated. There are other ways
to create the grid too. But for this example, we're
going to be using this package. We can use this anywhere
we create and render normal widgets. To define the grid, we need
to use the class called layout grid and generate a 12
columns with 1 fr or one fractional unit. A fractional unit is
similar to the way we use flex values with
expanded and flexible widgets. If you want the grid to
be responsive on mobile, you can grab the size
from the media query and create a four-column
grid instead of 12 on a certain breakpoint. To put the widgets
on the grid, you will use a different
way to lay them out than you may be used to. Typically, you would use column
and rows to create the layout. But here, we can
wrap the widgets with a grid placement class. This will let us specify the
column start and end as well as many other options. There are other helper
methods in this library that make this easier to use. Next, we can add a piece of
content aligned to the grid starting at the second
column and stopping at the 10th column. This layout would be
really hard to create in the typical Flexbox model. And you can imagine
as a design scales up how the grid helps us rethink
and organize our layout. You can alternatively use
the CSS-style grid areas if you wanted to find
the layout with a more declarative visual string. LIAM SPRADLIN:
Next, we can start focusing on the
parameters that make Pesto stand out as uniquely
Pesto starting with color. Pesto already has
defined brand colors. Specified in the
brand parameters as basil, pepper, and
pine nut, these green, orange, and cream color
swatches can easily be plugged into Material 3
to generate a color scheme for the entire app. Since Material focuses on
mapping the relationships between colors on
components, we can count on Pesto's brand
colors being carried through the interface in a way
that's consistent and respects our priorities when translating
a brand system into a Material design system. You might also notice
that the error color has been switched
from the default red to a darker gold color. When your brand
colors include hues that are close to typical
semantic meanings, in this case, red meaning
error, specific interventions can be made. In Pesto, we both avoid
confusion with brand colors and also choose a color for
errors that better suits the neutral look
of the background and changes the tone of error
messages in the process. In Material, we have tooling
to generate these color schemes in a variety of ways,
including generating them through the Material
Theme Builder on the web or getting a color
scheme directly in Figma with the Material
Theme Builder plugin, including new surface
rolls and fixed tones. RODY DAVIS: To build the
Pesto Theme in Flutter, we can compose a theme class
based on a theme extension. We can pass our brand
colors and font families that we will use
in the application as defined in the design. To make it easier to create
the custom themes in Flutter, we will be releasing
a package called Theme to have utility methods
to generate themes and include a variety of pre-built
themes to get started. First, create a theme by
instantiating the class called Material Theme. Next, we will add
our brand colors as defined in the design file. You can also extend the class
if you want a named theme and to keep all the
logic in one place, as well as adding
widget theme overrides. Next, we will add the
two fonts with a method that we will create later,
which will merge the two text themes together. We will also need to import
the Google Fonts package, which we will use to grab the
two font families that we will use to merge. Finally, after we
created the theme, we can simply return the light
and dark theme on the data class based on the light
and dark methods using the build context. LIAM SPRADLIN: Even in an app
with strong brand perspectives, like Pesto, there
may be moments where you want to add a
more expressive touch or allow the users
to have a more personalized experience
with content that they've added to the app. Both of these things
can be accomplished with content-based dynamic color
using the M3's dynamic color capabilities while preserving
your brand aesthetic. In this example screen, we
could color the entire interface based on the recipe photo which
has been uploaded by a user. In this case, the
Creamy Pesto Pasta photo is used to generate a new
screen-specific color scheme. Since the mappings are
consistent with the way that the main app
screens are mapped, the colors can change
without confusing users. RODY DAVIS: With the latest
version of Flutter and Material color utilities, we
have a new method for creating a color scheme. We can now create a color scheme
based on an image provider. The image provider can be an
asset, network, or memory image like you're used to now. And we can create a
color scheme that we will blend with the parent
theme of our application. First, we will need to grab
the current theme which contains our brightness
and current seed color. Next, we will create
an image provider based on the type of image used. In our application
since we're referencing images in the assets, we will be
using the asset image provider. Just like we can create a
color scheme from a seed color, now, we have this new method
to create the color scheme from the image provider. Simply pass in the provider
and the current color scheme brightness and return
the new color scheme. We are not blending the
theme here currently, but we can later if
we wish to harmonize the screen to the parent theme. Now that we have the new color
scheme, we can update the theme and pass it to the
theme widget as a data override for the subtree
looking for the closest theme. To blend the color
scheme, we will first need to import Material
color utilities. Then we can define a method
to accept the current scheme color from the parent theme
and the new one created based on the image provider. We can grab the two primaries
from each theme which we will use together to blend. Note that these colors will
be different on light and dark mode. Next, we can blend
the colors together with the blend function and
return the harmonized color back. Finally, return the
new color scheme based on that
harmonized seed color. LIAM SPRADLIN: Speaking as
an interface designer who's also a type designer, it's
really important to me to note that type or text in all
it's expression is interface. It serves so many
purposes in an interface from delivering content
to aiding and navigation all the way to the elements
that are nontextual but still typographic like icons. As we saw before, Pesto
already has its own brand fonts selected. Those are Montserrat and Lekton. In Material, you can plug these
typefaces into the type scale and see how they
behave as a theme. In this case, we've used
Montserrat for larger styles and Lekton for smaller ones. If your brand has pre-determined
type sizes and styles, you can make specific
interventions in the type scale to represent those
in the slots where they feel the most appropriate. Here's how our type
scale manifests in Pesto. You can really see the bulk
of information and affordances in the app are
communicated through type and consistently applying
different typefaces to different types
of information helps us quickly scan
through everything on screen and recognize what
we're looking at. RODY DAVIS: Flutter comes with
a default Roboto-based font. But we can really give
the app a personal look just by changing the
default font family. Taking it further, we
can use multiple fonts for headlines and subtitles
and bodies and captions. This is exactly what basil does. And we can create that now
with the text theme class. Let's walk through how
to create the theme data object for a given brightness. We can generate our color scheme
with a variety of methods. But here, we're
calling a function that takes the brand colors
and brightness and returns the scheme. Next, we can use a method to
merge the text theme based on two different fonts,
which, in this case, is Montserrat and Lekton. This method will be available
in the code linked at the end but simply sets the first font
to display and headline groups in the second font to the rest. This method also is available
in the final code linked at the end and would just
take a given text theme, override the color to be
on surface since it's not by default. Finally,
return the theme data with the correct color
brightness, color scheme, and text theme. Next, we'll talk about ways
to customize Material further for your app's
unique personality. The bulk of Pesto's interface
relies on Material components. Things, like, buttons,
FABs, chips, input fields, tabs, and navigation
components, all help users get around the app
in familiar predictable ways that are backed by
Material Design research. And there's a lot you can
customize about components while still preserving
that base usability. For example, mapping different
surface tones from our color scheme onto components to
create different visual effects emphasizing, deemphasizing, or
otherwise enriching the user's understanding of visual
elements by tweaking how they're presented in
relation to one another. There are other
visual touches that fall outside the realm
of componentization too, like elements
for communication. In the ingredients list,
a subtle dashed line colored by Material tokens
connects ingredient names with quantities. The layout of these two
pieces of information creates a rhythmic,
geometric shape. And the dashed line
helps fill the space and maintain clear
associations between them. RODY DAVIS: At its core,
this is conceptually just like a normal
table that stylized to fit Pesto's aesthetic. Visually, we can
add a dash border for a spacer element between
the items and an icon at the leading edge. Thinking about multiple ways
to present the same data will help your app
really stand out and highlight your
personal brand. We can even make
this into a custom component that will still
reference the Material tokens. If you want to see
a detailed example, check out the GitHub
repo linked at the end. LIAM SPRADLIN:
Finally, we always want to consider context. The ways that people can use
your app will depend on where, when, and how they're
trying to use it. This is important to consider
when building experiences for multiple platforms that will
operate in different contexts. For example, if we
wanted to translate Pesto for an ambient
device, which may also be sensitive to user
proximity, in cases like this, we see that the
relationship between screen size and information
density isn't always linear. On an ambient display,
we might actually want to remove many
affordances to focus on the most important
content, especially if we know that the user
is reading from far away. This is also where it
becomes important to account for different input modalities. If a user uses a keyboard,
switch, mouse, touch, or even voice to
interact with your app, it should be accounted
for in the way that your design is structured. The way that your layout
is structured, specifically how users traverse both
visually and physically from one item to the next, is
crucial information that's not always
contained in one mockup and requires extra documentation
to successfully translate to code. How the user reads an interface
may change based on the screen and how they navigate, whether
with a finger, controller, or watch dial will
change as well. If you want to dive even
deeper on these topics and put them to use in your
own app with Flutter and M3, check out all the links
in the description for the tools,
resources, and guidelines that you'll need to
build a great experience across devices. RODY DAVIS: Hopefully, now,
you have a better understanding of how to build
Pesto with adaptive and Material tokens in mind. Know that you can always create
Material-custom components that will still use the
Material Theme. If you want to find out
more, please check out the description below
and thanks for watching. [MUSIC PLAYING]