Design for every device with Flutter and Material 3

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[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]
Info
Channel: Material Design
Views: 12,594
Rating: undefined out of 5
Keywords: Google I/O, Google IO, IO, I/O, IO 23, I/O 23, Google I/O 23, Google IO 23, Google I/O 2023, Google IO 2023, IO 2023, Google New, Google Announcement, Google Developers, Developer, Development
Id: CfOlY36GWYU
Channel Id: undefined
Length: 18min 11sec (1091 seconds)
Published: Wed May 10 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.