Material 3 from design to deployment

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[MUSIC PLAYING] LIAM SPRADLIN: Hi, my name is Liam. I'm a senior design advocate at Google on Material Design. RODY DAVIS: And my name is Rody. A senior developer advocate at Google. LIAM SPRADLIN: Today, we'll be talking about translating a design into code. We'll be breaking down how to take a design from a Figma file to creating adaptive reusable components for Flutter that target all six supported platforms. An important thing to remember is that adaptive design is not just about the breakpoint and device target. When building a truly adaptive experience, there's a whole matrix of options to consider. For example, a tablet with a keyboard but no mouse, a desktop with only a touch screen, or a mobile version that's running on a desktop in free form. With Flutter, it's easy to create platform adaptations and build a flexible UI that's capable of targeting the correct platform and input method. To illustrate what this means, particularly as you build adaptive apps with Flutter, we've made a sample study. A recipe discovery app called 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 your tablet, and carry out the recipe on an ambient device like a Nest Hub. 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 people we're working with to bring it to life. Things like the grid structures that underlie our layouts, the navigation interactions we intend, theming and visual customization, and the motion and transitions that link everything together are just a few of the key aspects that we need to accurately and reliably convey to developers. In this talk, we'll walk through some of these key elements in reference to our example app and talk about how Flutter can preserve and convey your design intent. RODY DAVIS: From a developer's perspective, we tend to think about designs as a set of components that we can post together in higher order UIs. Flutter gives us the ability to build declaratively on every frame and any size. When targeting six platforms, there's a lot of things we need to consider such as input methods, touch targets, keyboard events, native menus, file handlers and more. We also need a translated design in Figma with dummy data into a working demo using mock data. This may be a tempting step to skip when building with Flutter. But by starting with dummy data, you can decouple your UI from the business logic and start working off of a few model style presentation. And finally, we need to think about all the animations not shown in Figma or even implicit ones for transitions throughout the app. Having a way to quickly test various animations is critical. One exciting update is the new Material 3 widgets for Flutter. There are multiple widgets that are included. And we'll be going over how to use them today. As we go through this talk, we're going to be building the Basil Theme together. This will cover theme extensions, custom fonts, dynamic color, and widget themes. First, let's create the Material 3 Theme class. Here, we're creating a immutable class with some brand colors that the design defines for us in a simple constructor. Brand colors, if you're not familiar with, are colors associated with the company and colors that make up the logo or related assets. For Google, this is the four colors that make up the G logo. Next, we create a callback for creating the theme data object. And we'll use that to pass to the theme for the Material app later. Available in the current version of Flutter, we can enable the use Material 3 theme override, which we will use for the new color system and update any supported widgets. After we have defined the class, we can then import it at the entry point of our application and instantiate the class. We then just call the two-theme data method and build the Basil theme, which we then provide to the widget tree. Later, we're going to be talking about ways in which we can theme the application with just the default widgets and theme overrides which allow for better reuse and extensibility. Next, we can take advantage of the theme data feature called Theme Extensions released in Flutter 3.0. To create a theme extension, simply extend the class we just created with the theme extension class and the type of our theme. This is required for when we pass it to the theme data class later and for providing it to the widget tree. We only need to override two methods. The first being the copyWith method. This is for when you're inside a widget and you want to override a single property and get a new theme back. Next, we can just override the alert method, which is used for animation. Just check to see if the type coming in is the class we're expecting and work through all the inputs. Now, back to Liam on typography. LIAM SPRADLIN: Speaking as an interface designer who's also a type designer, it's important to me to note that type or text in all its expression is interface. It serves so many purposes in an interface from delivering content to aiding in navigation, all the way to elements that are nontextual but still typographic, like icons. One big consideration is how you choose the type styles that best serve your content and layout. In space-constrained places, like navigation components, the right type style can allow you to communicate more clearly with users. Other type styles, like those found in materials type scale, can help you create and maintain consistent information hierarchies throughout your app and across devices. Titles, captions, body text, even inline links can instantly be recognized by users if your type scale carefully considers their styles. Making more nuanced choices about baseline grids, columns, spacing, and alignment can also contribute to the overall character of your experience, making it strict, geometric, and modern, or allowing it to be loose, free flowing, or even playful. RODY DAVIS: From a developer's perspective when translating a design, it is important to preserve the semantics around typography, emphasize, spacing, and type scale. It can be easy just to stick with the default textile in Flutter and just change the font size or alignment as needed. But there's a lot we can do to really polish UI. For most cases, you can get away with using the text widget in Flutter. But sometimes, a design will have a bolded word in the middle of a sentence. And for that, we can use the rich text widget. Also, in text-heavy apps, there's a dynamic list and styles such as in a markdown source. And for that, we can use the Flutter markdown package which will convert our inputs into widgets and rich text. Both of these are reasons why we want to have great custom text themes. Often, a design will have multiple font pairings that corresponds to titles and headlines or body and text. Flutter gives us the text theme class, which we can then use to define our type scale. And we can include any number of font families for the levels. To actually load the font, we can either include the font assets directly in our app and define them in the pubs of a Caml or use the Google Fonts Pub package and dynamically load them in. Using the Google Fonts package allows us to test different font pairings before optimizing for production build. First, we need to import the Google Fonts package in the file where we defined our theme. Next, we can create a new method, which returns the base theme data class, which we will then use for other contexts such as light and dark later. We can then import these two fonts defined in the design spec and create a merged theme, which we will then use to pass to the text theme class. Note that it is possible to override just a single level or groups of styles depending on the design intent. This package just requires internet access. So make sure to give the mac OS target if running the correct entitlements defining the package. That's it for typography. Next time we run the app, we will see Roboto updated with the new correct default textiles. LIAM SPRADLIN: One thing that we really focused on in the design updates for Material 3 is color. And a lot of the changes and improvements made to the material color system were motivated by creating and preserving design intent. Rather than defining each individual color for each individual visual element, we established a system that generates a comprehensive and cohesive color scheme based on the relationships between colors. This way, design intent for the meaning and function of different elements that can be communicated through color can be preserved throughout the process of building an interface. In Pesto, a recipe screen can even be themed based on the image associated with the recipe. In this case, the creamy pesto pasta translating the users or the recipe writer's unique intent into a cohesive version of the design intent that you've established and implemented. RODY DAVIS: From developer's perspective, Flutter makes working with dynamic color easy thanks to a great pub package called Material Color Utilities and the extensible theme data class. Lets build a custom color scheme together. Let's add the Material Color Utilities import above our theme to get access to the HCT color system. The Flutter SDK already depends on this package. But you will still want to add this to your pub spec dependencies. Let's create a method that returns a scheme that we can use to create a custom color scheme class. Sometimes, a design is only based on a single color. And for those instances, we can use a color scheme from seed, which gives us a beautiful generated color scheme using the ACT color space. For Basil, we have multiple brand colors that we need to use to create custom tonal groups from. First define a base palette that all tokens can inherit from if not overridden. Next, create the tertiary tonal group and note that the palette is returning the primary palette to provide the chromatic tonal group that the design was intending. Finally, create the neutral palette, which will also be used to override tokens. The color palette class comes from the Material Color Utilities and is a group of palettes that are derived from a single source color. Next, we will be adding tokens to the scheme class. You may not be familiar with the scheme class or the concept of design tokens. But the scheme class is a class in Material Color Utilities that has a one-to-one relationship with the color scheme class in Flutter. All these parameters are designed tokens, which are theme values that can be passed down and inherit from in subthemes. Here, we're just going to go quickly through the scheme and define the tokens from those palettes. For each of these tokens, we pulled them from the tonal palette and get a color based on a given tone of brightness. To learn more about the new token's material design, you can go to m3.material.io. Next, add the overrides for background, error group, outlines, and surfaces. Finally, add the overrides for surface variant and inverted colors. Note that for the dark theme, there needs to be different tones use for these tokens. For most cases, you will not need to create a custom color scheme. But this is an example of all the things done for you when you use the color scheme from seed method. We can also create an extension method on the scheme class to return a color scheme that the theme data class expects with a given brightness. Now, we can add the color scheme parameter to our base method and pass the color scheme to the theme data class. When overriding a token such as scaffold background, sometimes, the design will use a brand color instead of a derived token in the scheme. For this token, we're checking to see if its light, brightness, and returning the brand color defined earlier. Finally, we can compose the complete color scheme and the theme data class in two-theme data method while making sure to pass the brightness. Sometimes, we want to pull a theme from an image and have it match the main theme. For example, a music player app can pull from the album art and change the background to match. This color could be anything. But thanks to the Material Color Utilities, we can make sure that the color will meet contrast requirements and have a color scheme that will work with our app. In Pesto, we can use the image on the detail screen to create a content-based theme that matches the top level theme. To do this, we can create an image theme class, import Material Color Utilities, and the image package. Next, we create a method to take the image defined at the path, get the bytes, and convert them to an RGB pixel array with the image package. We can then implement some basic error handling. Then we can implement the source colors from image method that takes the pixel data, quantitizes the result, and returns them to the ranked pixels in the image. Now, we can create a color scheme from image method that takes the current color scheme and blends it with the primary of the top color in the image. We then can use that seed to generate another color scheme which we then return. This blend method is important because otherwise, the color could potentially clash with the main theme. Finally, we can use the method just to find to create a build method, which returns a FutureBuilder and creates a color scheme from the image. It then passes it to the theme widget, which will override the theme data in the widget subtree. Once we have defined all the colors and typography, we need to create individual widget theme overrides. This will help reduce the need for custom components or theming in the build method. Learning how to define these overrides properly will help the application have an experience that properly reflects the design intent. First, let's create the TabBarTheme-- then the FloatingActionButton override. Next, the NavigationRailThemeData. Note that these are just applying color overrides based on the design. Finally, override the AppBar and ChipTheme. There are many widgets that we did not override. But it's because we're not using them yet or the default to Material 3 appear correct. LIAM SPRADLIN: Of course, the ways that people can use your app will depend on where, when, and how they're using it. This is where it becomes really important to account for different input modalities. If a user has a keyboard, switch, mouse, touch, or even voice to interact with your app, it should be accounted for in the way your design is structured. The way your layout is structured, specifically how users traverse both visually and physically from one item to the next is crucial information that's not captured in one static mockup and requires extra documentation to successfully translate into implementation. And this might change based on what device your app is running on. Layout density might be lower on an ambient device that's viewed from far away and has less need for touch input. This will mean quicker traversal through fewer onscreen elements. On a phone, the density may increase. But things like touch targets become more important to consider. Across devices, the navigation structure may change as you gain or lose screen space. RODY DAVIS: From a developer's perspective, we should be mindful about where the application is intended to be deployed. In Flutter, you can define multiple entry points depending on the target you're building for. Rather than building a single UI package in binary that's meant to run in all these contexts, you can compose the UI and functionality depending on which top-level app you pass to runApp. In your theme data class, you can pass adaptive platform density Enum to the visual density override to create a more compact UI in these contexts where input is more precise. And when it comes to traversal and touch targets, it is important to remember that building a great accessible app is good for keyboard navigation and accessible touch targets. Flutter has a good focus traversal. And if you're using the default focus nodes defined in most widgets, you can test them by using the Tab and Shift Tab keys to navigate. Make sure to define tool tips and meaningful semantics where possible throughout the widget tree. For navigation, you can use the go router package to split up the routes into files and have fine-grained control with the new Navigator 2.0 class. This is what the Flutter app looks like running without our theme applied. But when passing the theme to the Material app, we get a beautiful Basil Material 3 theme in Flutter. The theme data class is very powerful and allows us to create truly custom themes that match the brand or design spec handed off to the developer. Sometimes, a theme for a widget is not available. And for that, we can use extensions and custom widgets. LIAM SPRADLIN: If you still find the concept of building a custom theme challenging or just need somewhere to get started with your design, check out the Material Theme Builder and export your theme for Flutter. You can also learn more about Material 3 and Material.io. Thanks for watching. [MUSIC PLAYING]
Info
Channel: Flutter
Views: 62,630
Rating: undefined out of 5
Keywords: flutter forward, flutter forward 2023, flutter latest, flutter updates, what's new in flutter, how to use flutter, introduction to flutter, intro to flutter, flutter tutorial, flutter developer, flutter developers, google developer, google developers, google, flutter, dart, dash
Id: 7nrhTdS7dHg
Channel Id: undefined
Length: 16min 10sec (970 seconds)
Published: Wed Jan 25 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.