CINXE.COM
Your first Flutter app | Google Codelabs
<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="721724668570-nbkv1cfusk7kk4eni4pjvepaus73b13t.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="Google Codelabs"> <meta property="og:type" content="website"><meta name="theme-color" content="#1a73e8"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/codelabs/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/css/app.css"> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/favicon.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/touchicon-180.png"><link rel="canonical" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first"><link rel="search" type="application/opensearchdescription+xml" title="Google Codelabs" href="https://codelabs.developers.google.com/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first" /><link rel="alternate" hreflang="x-default" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first" /><link rel="alternate" hreflang="ar" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=ar" /><link rel="alternate" hreflang="bn" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=bn" /><link rel="alternate" hreflang="zh-Hans" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=zh-tw" /><link rel="alternate" hreflang="fa" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=fa" /><link rel="alternate" hreflang="fr" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=fr" /><link rel="alternate" hreflang="de" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=de" /><link rel="alternate" hreflang="he" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=he" /><link rel="alternate" hreflang="hi" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=hi" /><link rel="alternate" hreflang="id" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=id" /><link rel="alternate" hreflang="it" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=it" /><link rel="alternate" hreflang="ja" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=ja" /><link rel="alternate" hreflang="ko" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=ko" /><link rel="alternate" hreflang="pl" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=pl" /><link rel="alternate" hreflang="pt-BR" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=pt-br" /><link rel="alternate" hreflang="ru" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=ru" /><link rel="alternate" hreflang="es-419" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=es-419" /><link rel="alternate" hreflang="th" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=th" /><link rel="alternate" hreflang="tr" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=tr" /><link rel="alternate" hreflang="vi" href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=vi" /><title>Your first Flutter app | Google Codelabs</title> <meta property="og:title" content="Your first Flutter app | Google Codelabs"><meta name="description" content="In this codelab, you’ll learn how to build a Flutter app that generates random, cool-sounding names."> <meta property="og:description" content="In this codelab, you’ll learn how to build a Flutter app that generates random, cool-sounding names."><meta property="og:url" content="https://codelabs.developers.google.com/codelabs/flutter-codelab-first"><meta property="og:locale" content="en"> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="codelab" theme="codelabs-theme" type="codelab" layout="docs" display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner"> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="googleCodelabs" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup.svg" class="devsite-site-logo" alt="Google Codelabs"> </picture> </a> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion tenant-name="Google Codelabs" > <form class="devsite-search-form" action="https://codelabs.developers.google.com/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <devsite-user enable-profiles fp-auth id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars hidden> <div class="devsite-book-nav-filter" hidden> <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="googleCodelabs" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup.svg" class="devsite-site-logo" alt="Google Codelabs"> </picture> </a> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" has-sidebar > <div class="devsite-sidebar"> <div class="devsite-sidebar-content"> <devsite-toc class="devsite-nav" role="navigation" aria-label="On this page" depth="1" scrollbars ></devsite-toc> <devsite-recommendations-sidebar class="nocontent devsite-nav"> </devsite-recommendations-sidebar> </div> </div> <devsite-content> <article class="devsite-article"><style> body { transition: opacity ease-in 0.2s; } body[unresolved] { opacity: 0; display: block; overflow: hidden; position: relative; } </style> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" > </ul> </div> <h1 class="devsite-page-title" tabindex="-1"> Your first Flutter app </h1> <devsite-toc class="devsite-nav" depth="1" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <google-codelab-analytics gaid="UA-49880327-14" ga4id="G-JTFZSJVVVZ"></google-codelab-analytics> <google-codelab codelab-gaid="" codelab-ga4id="" doc-id="1mmGKqMbcQNGdZqsUn1NKiPIsVnc7wTP2DRp2Y_Ms-wk" id="codelabs/flutter-codelab-first" title="Your first Flutter app" no-tooltip="" environment="web" category="" feedback-link="https://github.com/flutter/flutter/issues" layout="paginated" > <google-codelab-step label="Introduction" duration="0" step="0"> <google-codelab-about codelab-title="Your first Flutter app" authors="Filip Hracek" last-updated="2024-05-12T22:42:13Z" duration="85"> </google-codelab-about> <h2 class="step-title" id="0" data-text="Introduction" tabindex="-1"> 1. Introduction </h2> <p>Flutter is Google's UI toolkit for building applications for mobile, web, and desktop from a single codebase. In this codelab, you will build the following Flutter application:</p> <devsite-youtube video-id="jj5yBVwnEQw"></devsite-youtube> <p>The application generates cool-sounding names, such as "newstay", "lightstream", "mainbrake", or "graypine". The user can ask for the next name, favorite the current one, and review the list of favorited names on a separate page. The app is responsive to different screen sizes.</p> <h2 class="checklist" is-upgraded id="what-youll-learn" data-text="What you'll learn" tabindex="-1">What you'll learn</h2> <ul class="checklist"> <li>The basics of how Flutter works</li> <li>Creating layouts in Flutter</li> <li>Connecting user interactions (like button presses) to app behavior</li> <li>Keeping your Flutter code organized</li> <li>Making your app responsive (for different screens)</li> <li>Achieving a consistent look & feel of your app</li> </ul> <p>You'll start with a basic scaffold so that you can jump straight to the interesting parts.</p> <p class="image-container"><img alt="e9c6b402cd8003fd.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e9c6b402cd8003fd_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>And here is Filip taking you through the whole codelab!</p> <devsite-youtube video-id="8sAyPDLorek"></devsite-youtube> <p>Click next to start the lab.</p> </google-codelab-step> <google-codelab-step label="Set up your Flutter environment" duration="10" step="1"> <h2 class="step-title" id="1" data-text="Set up your Flutter environment" tabindex="-1"> 2. Set up your Flutter environment </h2> <h2 is-upgraded id="editor" data-text="Editor" tabindex="-1">Editor</h2> <p>To make this codelab as straightforward as possible, we assume you'll use <strong>Visual Studio Code</strong> (VS Code) as your development environment. It's free and works on all major platforms.</p> <p><a href="https://code.visualstudio.com/download" target="_blank"><button class="button button-primary button-with-icon"><span class="material-icons" aria-hidden="true" translate="no">file_download</span>Download Visual Studio Code</button></a></p> <p>Of course it's fine to use any editor you like: Android Studio, other IntelliJ IDEs, Emacs, Vim, or Notepad++. They all work with Flutter.</p> <p>We recommend using VS Code for this codelab because the instructions default to VS Code-specific shortcuts. It's easier to say things like "click here" or "press this key" instead of something like "do the appropriate action in your editor to do X".</p> <p class="image-container"><img alt="228c71510a8e868.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/228c71510a8e868.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/228c71510a8e868_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 is-upgraded id="choose-a-development-target" data-text="Choose a development target" tabindex="-1">Choose a development target</h2> <p>Flutter is a multi-platform toolkit. Your app can run on any of the following operating systems:</p> <ul> <li>iOS</li> <li>Android</li> <li>Windows</li> <li>macOS</li> <li>Linux</li> <li>web</li> </ul> <p>However, it's common practice to choose a single operating system for which you will <em>primarily</em> develop. This is your "development target"—the operating system that your app runs on during development.</p> <p class="image-container"><img alt="16695777c07f18e5.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/16695777c07f18e5.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/16695777c07f18e5_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>For example, say you're using a Windows laptop to develop a Flutter app. If you choose Android as your development target, you typically attach an Android device to your Windows laptop with a USB cable, and your app-in-development runs on that attached Android device. But you could also choose Windows as the development target, which means your app-in-development runs as a Windows app alongside your editor.</p> <aside class="special"><p><strong>Tip</strong>: We strongly recommend choosing your development device's Operating System as your development target. So, for example, if your computer runs Windows, choose Windows as the development target.</p> <p class="image-container"><img alt="d5d32cbb81d8de60.png" style="width: 610.00px" src="/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d5d32cbb81d8de60_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </aside> <p>It might be tempting to select the web as your development target. The downside of this choice is that you lose one of Flutter's most useful development features: Stateful Hot Reload. Flutter can't hot-reload web applications.</p> <p>Make your choice now. Remember: You can always run your app on other operating systems later. It's just that having a clear development target in mind makes the next step smoother.</p> <h2 is-upgraded id="install-flutter" data-text="Install Flutter" tabindex="-1">Install Flutter</h2> <p>The most up-to-date instructions on how to install the Flutter SDK are always at <a href="https://docs.flutter.dev/" target="_blank">docs.flutter.dev</a>.</p> <p><a href="https://docs.flutter.dev/get-started/install" target="_blank"><button class="button button-primary">Install Flutter SDK</button></a></p> <p>The instructions on the Flutter website cover not only the installation of the SDK itself, but also the development target-related tools and the editor plugins. Remember that, for this codelab, you only need to install the following:</p> <ol type="1"> <li>Flutter SDK</li> <li>Visual Studio Code with the Flutter plugin</li> <li>The software required by your chosen development target (for example: <em>Visual Studio</em> to target Windows, or <em>Xcode</em> to target macOS)</li> </ol> <p>In the next section, you'll create your first Flutter project.</p> <p>If you've had problems so far, you might find some of these questions and answers (from StackOverflow) helpful for troubleshooting.</p> <h3 class="faq" is-upgraded id="frequently-asked-questions" data-text="Frequently Asked Questions" tabindex="-1"><strong>Frequently Asked Questions</strong></h3> <ul class="faq"> <li><a href="https://stackoverflow.com/questions/50236128/how-to-find-the-path-of-flutter-sdk" target="_blank">How do I find the path of the Flutter SDK?</a></li> <li><a href="https://stackoverflow.com/questions/50652071/flutter-command-not-found" target="_blank">What do I do when the Flutter command is not found?</a></li> <li><a href="https://stackoverflow.com/questions/51679269/waiting-for-another-flutter-command-to-release-the-startup-lock" target="_blank">How do I fix the "Waiting for another flutter command to release the startup lock" issue?</a></li> <li><a href="https://stackoverflow.com/questions/59647791/android-studio-not-installed-when-run-flutter-doctor-while-android-studio-in" target="_blank">How do I tell Flutter where my Android SDK installation is?</a></li> <li><a href="https://stackoverflow.com/questions/61993738/flutter-doctor-android-licenses-gives-a-java-error" target="_blank">How do I deal with the Java error when running <code translate="no" dir="ltr">flutter doctor --android-licenses</code>?</a></li> <li><a href="https://stackoverflow.com/questions/60475481/flutter-doctor-error-android-sdkmanager-tool-not-found-windows/" target="_blank">How do I deal with Android <code translate="no" dir="ltr">sdkmanager</code> tool not found?</a></li> <li><a href="https://stackoverflow.com/questions/68236007/i-am-getting-error-cmdline-tools-component-is-missing-after-installing-flutter" target="_blank">How do I deal with the "<code translate="no" dir="ltr">cmdline-tools</code> component is missing" error?</a></li> <li><a href="https://stackoverflow.com/questions/64901180/how-to-run-cocoapods-on-apple-silicon-m1" target="_blank">How do I run CocoaPods on Apple Silicon (M1)?</a></li> <li><a href="https://stackoverflow.com/questions/62889725/disable-autoformat-in-vs-code-for-dart" target="_blank">How do I disable autoformatting on save in VS Code?</a></li> </ul> </google-codelab-step> <google-codelab-step label="Create a project" duration="5" step="2"> <h2 class="step-title" id="2" data-text="Create a project" tabindex="-1"> 3. Create a project </h2> <h2 is-upgraded id="create-your-first-flutter-project" data-text="Create your first Flutter project" tabindex="-1">Create your first Flutter project</h2> <p>Launch Visual Studio Code and open the command palette (with <code translate="no" dir="ltr">F1</code> or <code translate="no" dir="ltr">Ctrl+Shift+P</code> or <code translate="no" dir="ltr">Shift+Cmd+P</code>). Start typing "flutter new". Select the <strong>Flutter: New Project</strong> command.</p> <devsite-youtube video-id="rifRX4G1LyY"></devsite-youtube> <p>Next, select <strong>Application</strong> and then a folder in which to create your project. This could be your home directory, or something like <code translate="no" dir="ltr">C:\src\</code>.</p> <p>Finally, name your project. Something like <code translate="no" dir="ltr">namer_app</code> or <code translate="no" dir="ltr">my_awesome_namer</code>.</p> <p class="image-container"><img alt="260a7d97f9678005.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/260a7d97f9678005.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/260a7d97f9678005_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Flutter now creates your project folder and VS Code opens it.</p> <aside class="warning"><p><strong>Note:</strong> VS Code shows a modal window asking whether to trust the contents of the folder.</p> <p class="image-container"><img alt="756a9586aacb2bda.png" style="width: 456.50px" src="/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/756a9586aacb2bda_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Select <strong>Yes</strong>. The other option disables substantial Flutter functionality.</p> </aside> <p>You'll now overwrite the contents of 3 files with a basic scaffold of the app.</p> <h2 is-upgraded id="copy-paste-the-initial-app" data-text="Copy & Paste the initial app" tabindex="-1">Copy & Paste the initial app</h2> <p>In the left pane of VS Code, make sure that <strong>Explorer</strong> is selected, and open the <code translate="no" dir="ltr">pubspec.yaml</code> file.</p> <p class="image-container"><img alt="e2a5bab0be07f4f7.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e2a5bab0be07f4f7_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Replace the contents of this file with the following:</p> <h3 is-upgraded id="pubspec.yaml" data-text="pubspec.yaml" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_03/pubspec.yaml" target="_blank">pubspec.yaml</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="ActionScript 3"><code translate="no" dir="ltr"><span class="devsite-syntax-n">name</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">namer_app</span> <span class="devsite-syntax-n">description</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">A</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">new</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Flutter</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">project</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-n">publish_to</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'none'</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">#</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Remove</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">you</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">wish</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">publish</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pub</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-na">dev</span> <span class="devsite-syntax-n">version</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mf">0.0</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-mi">1</span><span class="devsite-syntax-o">+</span><span class="devsite-syntax-mi">1</span> <span class="devsite-syntax-n">environment</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">sdk</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">^</span><span class="devsite-syntax-mf">3.1</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-mi">1</span> <span class="devsite-syntax-n">dependencies</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">flutter</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">sdk</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">flutter</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">english_words</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">^</span><span class="devsite-syntax-mf">4.0</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-mi">0</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">provider</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">^</span><span class="devsite-syntax-mf">6.0</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-mi">0</span> <span class="devsite-syntax-n">dev_dependencies</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">flutter_test</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">sdk</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">flutter</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">flutter_lints</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">^</span><span class="devsite-syntax-mf">2.0</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-mi">0</span> <span class="devsite-syntax-n">flutter</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">uses</span><span class="devsite-syntax-o">-</span><span class="devsite-syntax-n">material</span><span class="devsite-syntax-o">-</span><span class="devsite-syntax-n">design</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">true</span> </code></pre></devsite-code> <p>The <code translate="no" dir="ltr">pubspec.yaml</code> file specifies basic information about your app, such as its current version, its dependencies, and the assets with which it will ship.</p> <aside class="special"><p><strong>Note</strong>: If you gave your app a name other than <code translate="no" dir="ltr">namer_app</code>, you need to change the first line correspondingly.</p> </aside> <p>Next, open another configuration file in the project, <code translate="no" dir="ltr">analysis_options.yaml</code>.</p> <p class="image-container"><img alt="a781f218093be8e0.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/a781f218093be8e0.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a781f218093be8e0_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Replace its contents with the following:</p> <h3 is-upgraded id="analysis_options.yaml" data-text="analysis_options.yaml" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_03/analysis_options.yaml" target="_blank">analysis_options.yaml</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="ActionScript 3"><code translate="no" dir="ltr"><span class="devsite-syntax-k">include</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">package</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-n">flutter_lints</span><span class="devsite-syntax-o">/</span><span class="devsite-syntax-n">flutter</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-na">yaml</span> <span class="devsite-syntax-n">linter</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">rules</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">avoid_print</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">false</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">prefer_const_constructors_in_immutables</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">false</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">prefer_const_constructors</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">false</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">prefer_const_literals_to_create_immutables</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">false</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">prefer_final_fields</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">false</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">unnecessary_breaks</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">true</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">use_key_in_widget_constructors</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kc">false</span> </code></pre></devsite-code> <p>This file determines how strict Flutter should be when analyzing your code. Since this is your first foray into Flutter, you're telling the analyzer to take it easy. You can always tune this later. In fact, as you get closer to publishing an actual production app, you will almost certainly want to make the analyzer stricter than this.</p> <p>Finally, open the <code translate="no" dir="ltr">main.dart</code> file under the <code translate="no" dir="ltr">lib/</code> directory.</p> <p class="image-container"><img alt="e54c671c9bb4d23d.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e54c671c9bb4d23d_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Replace the contents of this file with the following:</p> <h3 is-upgraded id="libmain.dart" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_03/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code translate="no" dir="ltr"><span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'package:english_words/english_words.dart'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'package:flutter/material.dart'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'package:provider/provider.dart'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-n">void</span> <span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">()</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">runApp</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">MyApp</span><span class="devsite-syntax-p">());</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">MyApp</span> <span class="devsite-syntax-n">extends</span> <span class="devsite-syntax-n">StatelessWidget</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">MyApp</span><span class="devsite-syntax-p">({</span><span class="devsite-syntax-nb">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-nd">@override</span> <span class="devsite-syntax-n">Widget</span> <span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span> <span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-k">return</span> <span class="devsite-syntax-n">ChangeNotifierProvider</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">create</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-o">=</span>> <span class="devsite-syntax-n">MyAppState</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">MaterialApp</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-s1">'Namer App'</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">theme</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">ThemeData</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">useMaterial3</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">true</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">ColorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">fromSeed</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">seedColor</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">Colors</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">deepOrange</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">MyAppState</span> <span class="devsite-syntax-n">extends</span> <span class="devsite-syntax-n">ChangeNotifier</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">var</span> <span class="devsite-syntax-n">current</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">random</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">MyHomePage</span> <span class="devsite-syntax-n">extends</span> <span class="devsite-syntax-n">StatelessWidget</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-nd">@override</span> <span class="devsite-syntax-n">Widget</span> <span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span> <span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">var</span> <span class="devsite-syntax-n">appState</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-k">return</span> <span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-p">[</span> <span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'A random idea:'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">],</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>These 50 lines of code are the entirety of the app so far.</p> <aside class="special"><p><strong>Note</strong>: This codelab is racing ahead to a point where you can start interactively changing the app—because that's the best way to learn Flutter. If you're missing an explanation of the code above, please be patient: it's coming.</p> </aside> <p>In the next section, run the application in debug mode and start developing.</p> </google-codelab-step> <google-codelab-step label="Add a button" duration="15" step="3"> <h2 class="step-title" id="3" data-text="Add a button" tabindex="-1"> 4. Add a button </h2> <p>This step adds a <strong>Next</strong> button to generate a new word pairing.</p> <h2 is-upgraded id="launch-the-app" data-text="Launch the app" tabindex="-1">Launch the app</h2> <p>First, open <code translate="no" dir="ltr">lib/main.dart</code> and make sure that you have your target device selected. At the bottom right corner of VS Code, you'll find a button that shows the current target device. Click to change it.</p> <devsite-youtube video-id="sp1qiM2Lg1o"></devsite-youtube> <p>While <code translate="no" dir="ltr">lib/main.dart</code> is open, find the "play" <img alt="b0a5d0200af5985d.png" style="width: 20.00px" src="/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b0a5d0200af5985d_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"> button in the upper right-hand corner of VS Code's window, and click it.</p> <devsite-youtube video-id="7-kfneb4X7s"></devsite-youtube> <p>After about a minute, your app launches in debug mode. It doesn't look like much yet:</p> <p class="image-container"><img alt="f96e7dfb0937d7f4.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f96e7dfb0937d7f4_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <aside class="special"><p><strong>Note</strong>: If your development target is a mobile device, it's possible that the text is partly obscured by a notch or a status bar. You will learn how to fix this soon.</p> </aside> <h2 is-upgraded id="first-hot-reload" data-text="First Hot Reload" tabindex="-1">First Hot Reload</h2> <p>At the bottom of <code translate="no" dir="ltr">lib/main.dart</code>, add something to the string in the first <code translate="no" dir="ltr">Text</code> object, and save the file (with <code translate="no" dir="ltr">Ctrl+S</code> or <code translate="no" dir="ltr">Cmd+S</code>). For example:</p> <h3 is-upgraded id="libmain.dart_1" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_a_widget/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'A random AWESOME idea:'</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// ← Example change.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-c1">// ...</span> </code></pre></devsite-code> <p>Notice how the app changes immediately but the random word stays the same. This is Flutter's famous <em>stateful Hot Reload</em> at work. Hot reload is triggered when you save changes to a source file.</p> <devsite-youtube video-id="p8w7M_w_AQY"></devsite-youtube> <h3 class="faq" is-upgraded id="frequently-asked-questions_1" data-text="Frequently Asked Questions" tabindex="-1">Frequently Asked Questions</h3> <ul class="faq"> <li><a href="https://stackoverflow.com/questions/54284047/vscode-hot-reload-for-flutter-does-not-work" target="_blank">What if Hot Reload doesn't work in VSCode?</a></li> <li><a href="https://stackoverflow.com/questions/49210769/vscode-hot-reload-for-flutter" target="_blank">Do I have to press ‘r' for hot reload in VSCode?</a></li> <li><a href="https://stackoverflow.com/questions/58580517/flutter-web-does-hot-restart-instead-of-hot-reload-is-hot-reload-supporte" target="_blank">Does Hot Reload work on the web?</a></li> <li><a href="https://stackoverflow.com/a/65166424/1416886" target="_blank">How do I remove the "Debug" banner?</a></li> </ul> <h2 is-upgraded id="adding-a-button" data-text="Adding a button" tabindex="-1">Adding a button</h2> <p>Next, add a button at the bottom of the <code translate="no" dir="ltr">Column</code>, right below the second <code translate="no" dir="ltr">Text</code> instance.</p> <h3 is-upgraded id="libmain.dart_2" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_a_widget/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'A random AWESOME idea:'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// ↓ Add this.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">print</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'button pressed!'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-c1">// ...</span> </code></pre></devsite-code> <p>When you save the change, the app updates again: A button appears and, when you click it, the <em>Debug Console</em> in VS Code shows a <strong>button pressed!</strong> message.</p> <devsite-youtube video-id="E2QSTLnvulc"></devsite-youtube> <h2 is-upgraded id="a-flutter-crash-course-in-5-minutes" data-text="A Flutter crash course in 5 minutes" tabindex="-1">A Flutter crash course in 5 minutes</h2> <p>As much fun as it is to watch the <em>Debug Console</em>, you want the button to do something more meaningful. Before getting to that, though, take a closer look at the code in <code translate="no" dir="ltr">lib/main.dart</code>, to understand how it works.</p> <h3 is-upgraded id="libmain.dart_3" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_a_widget/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-n">void</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">runApp</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">MyApp</span><span class="devsite-syntax-p">());</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-c1">// ...</span> </code></pre></devsite-code> <p>At the very top of the file, you'll find the <code translate="no" dir="ltr">main()</code> function. In its current form, it only tells Flutter to run the app defined in <code translate="no" dir="ltr">MyApp</code>.</p> <h3 is-upgraded id="libmain.dart_4" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_a_widget/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyApp</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyApp</span><span class="devsite-syntax-p">({</span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ChangeNotifierProvider</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">create</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyAppState</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MaterialApp</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'Namer App'</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ThemeData</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">useMaterial3</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">true</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ColorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">fromSeed</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">seedColor</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Colors</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">deepOrange</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>The <code translate="no" dir="ltr">MyApp</code> class extends <code translate="no" dir="ltr">StatelessWidget</code>. Widgets are the elements from which you build every Flutter app. As you can see, even the <em>app itself</em> is a widget.</p> <aside class="special"><p><strong>Note</strong>: We'll get to the explanation of <code translate="no" dir="ltr">StatelessWidget</code> (versus <code translate="no" dir="ltr">StatefulWidget</code>) later.</p> </aside> <p>The code in <code translate="no" dir="ltr">MyApp</code> sets up the whole app. It creates the app-wide state (more on this later), names the app, defines the visual theme, and sets the "home" widget—the starting point of your app.</p> <h3 is-upgraded id="libmain.dart_5" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_a_widget/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyAppState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ChangeNotifier</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">random</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Next, the <code translate="no" dir="ltr">MyAppState</code> class defines the app's...well...state. This is your first foray into Flutter, so this codelab will keep it simple and focused. There are many powerful ways to manage app state in Flutter. One of the easiest to explain is <code translate="no" dir="ltr">ChangeNotifier</code>, the approach taken by this app.</p> <ul> <li><code translate="no" dir="ltr">MyAppState</code> defines the data the app needs to function. Right now, it only contains a single variable with the current random word pair. You will add to this later.</li> <li>The state class extends <code translate="no" dir="ltr">ChangeNotifier</code>, which means that it can <em>notify</em> others about its own <em>changes</em>. For example, if the current word pair changes, some widgets in the app need to know.</li> <li>The state is created and provided to the whole app using a <code translate="no" dir="ltr">ChangeNotifierProvider</code> (see code above in <code translate="no" dir="ltr">MyApp</code>). This allows any widget in the app to get hold of the state. <img alt="d9b6ecac5494a6ff.png" style="width: 564.55px" src="/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d9b6ecac5494a6ff_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></li> </ul> <h3 is-upgraded id="libmain.dart_6" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_a_widget/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">1</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">2</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">3</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">4</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'A random AWESOME idea:'</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">5</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">6</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">print</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'button pressed!'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">7</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Lastly, there's <code translate="no" dir="ltr">MyHomePage</code>, the widget you've already modified. Each numbered line below maps to a line-number comment in the code above:</p> <ol type="1"> <li>Every widget defines a <code translate="no" dir="ltr">build()</code> method that's automatically called every time the widget's circumstances change so that the widget is always up to date.</li> <li><code translate="no" dir="ltr">MyHomePage</code> tracks changes to the app's current state using the <code translate="no" dir="ltr">watch</code> method.</li> <li>Every <code translate="no" dir="ltr">build</code> method must return a widget or (more typically) a nested <em>tree</em> of widgets. In this case, the top-level widget is <code translate="no" dir="ltr">Scaffold</code>. You aren't going to work with <code translate="no" dir="ltr">Scaffold</code> in this codelab, but it's a helpful widget and is found in the vast majority of real-world Flutter apps.</li> <li><code translate="no" dir="ltr">Column</code> is one of the most basic layout widgets in Flutter. It takes any number of children and puts them in a column from top to bottom. By default, the column visually places its children at the top. You'll soon change this so that the column is centered.</li> <li>You changed this <code translate="no" dir="ltr">Text</code> widget in the first step.</li> <li>This second <code translate="no" dir="ltr">Text</code> widget takes <code translate="no" dir="ltr">appState</code>, and accesses the only member of that class, <code translate="no" dir="ltr">current</code> (which is a <code translate="no" dir="ltr">WordPair</code>). <code translate="no" dir="ltr">WordPair</code> provides several helpful getters, such as <code translate="no" dir="ltr">asPascalCase</code> or <code translate="no" dir="ltr">asSnakeCase</code>. Here, we use <code translate="no" dir="ltr">asLowerCase</code> but you can change this now if you prefer one of the alternatives.</li> <li>Notice how Flutter code makes heavy use of trailing commas. This particular comma doesn't need to be here, because <code translate="no" dir="ltr">children</code> is the last (and also <em>only</em>) member of this particular <code translate="no" dir="ltr">Column</code> parameter list. Yet it is generally a good idea to use trailing commas: they make adding more members trivial, and they also serve as a hint for Dart's auto-formatter to put a newline there. For more information, see <a href="https://docs.flutter.dev/development/tools/formatting" target="_blank">Code formatting</a>.</li> </ol> <p>Next, you'll connect the button to the state.</p> <h2 is-upgraded id="your-first-behavior" data-text="Your first behavior" tabindex="-1">Your first behavior</h2> <p>Scroll to <code translate="no" dir="ltr">MyAppState</code> and add a <code translate="no" dir="ltr">getNext</code> method.</p> <h3 is-upgraded id="libmain.dart_7" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_b_behavior/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyAppState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ChangeNotifier</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">random</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">void</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">random</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">notifyListeners</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>The new <code translate="no" dir="ltr">getNext()</code> method reassigns <code translate="no" dir="ltr">current</code> with a new random <code translate="no" dir="ltr">WordPair</code>. It also calls <code translate="no" dir="ltr">notifyListeners()</code>(a method of <code translate="no" dir="ltr">ChangeNotifier)</code>that ensures that anyone watching <code translate="no" dir="ltr">MyAppState</code> is notified.</p> <p>All that remains is to call the <code translate="no" dir="ltr">getNext</code> method from the button's callback.</p> <h3 is-upgraded id="libmain.dart_8" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_04_b_behavior/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Scilab"><code translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// ← This instead of print().</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-c1">// ...</span> </code></pre></devsite-code> <p>Save and try the app now. It should generate a new random word pair every time you press the <strong>Next</strong> button.</p> <p>In the next section, you'll make the user interface prettier.</p> </google-codelab-step> <google-codelab-step label="Make the app prettier" duration="15" step="4"> <h2 class="step-title" id="4" data-text="Make the app prettier" tabindex="-1"> 5. Make the app prettier </h2> <p>This is how the app looks at the moment.</p> <p class="image-container"><img alt="3dd8a9d8653bdc56.png" style="width: 415.79px" src="/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3dd8a9d8653bdc56_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Not great. The centerpiece of the app—the randomly generated pair of words—should be more visible. It is, after all, the main reason our users are using this app! Also, the app contents are weirdly off-center, and the whole app is boringly black & white.</p> <p>This section addresses these issues by working on the app's design. The end goal for this section is something like the following:</p> <p class="image-container"><img alt="2bbee054d81a3127.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2bbee054d81a3127_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 is-upgraded id="extract-a-widget" data-text="Extract a widget" tabindex="-1">Extract a widget</h2> <p>The line responsible for showing the current word pair looks like this now: <code translate="no" dir="ltr">Text(appState.current.asLowerCase)</code>. To change it into something more complex, it's a good idea to extract this line into a separate widget. Having separate widgets for separate logical parts of your UI is an important way of managing complexity in Flutter.</p> <p>Flutter provides a refactoring helper for extracting widgets but before you use it, make sure that the line being extracted only accesses what it needs. Right now, the line accesses <code translate="no" dir="ltr">appState</code>, but really only needs to know what the current word pair is.</p> <p>For that reason, rewrite the <code translate="no" dir="ltr">MyHomePage</code> widget as follows:</p> <h3 is-upgraded id="libmain.dart_9" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_a_pair/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span><span class="devsite-syntax-w"> </span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">;</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'A random AWESOME idea:'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Change</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Nice. The <code translate="no" dir="ltr">Text</code> widget no longer refers to the whole <code translate="no" dir="ltr">appState</code>.</p> <p>Now, call up the <strong>Refactor</strong> menu. In VS Code, you do this in one of two ways:</p> <ol type="1"> <li>Right click the piece of code you want to refactor (<code translate="no" dir="ltr">Text</code> in this case) and select <strong>Refactor...</strong> from the drop-down menu,</li> </ol> <p>OR</p> <ol type="1" start="2"> <li>Move your cursor to the piece code you want to refactor (<code translate="no" dir="ltr">Text</code>, in this case), and press <code translate="no" dir="ltr">Ctrl+.</code> (Win/Linux) or <code translate="no" dir="ltr">Cmd+.</code> (Mac).</li> </ol> <devsite-youtube video-id="9BhqIPMOEIM"></devsite-youtube> <p>In the <strong>Refactor</strong> menu, select <strong>Extract Widget</strong>. Assign a name, such as <strong>BigCard</strong>, and click <code translate="no" dir="ltr">Enter</code>.</p> <p>This automatically creates a new class, <code translate="no" dir="ltr">BigCard</code>, at the end of the current file. The class looks something like the following:</p> <h3 is-upgraded id="libmain.dart_10" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_b_extract/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Notice how the app keeps working even through this refactoring.</p> <h2 is-upgraded id="add-a-card" data-text="Add a Card" tabindex="-1">Add a Card</h2> <p>Now it's time to make this new widget into the bold piece of UI we envisioned at the beginning of this section.</p> <p>Find the <code translate="no" dir="ltr">BigCard</code> class and the <code translate="no" dir="ltr">build()</code> method within it. As before, call up the <strong>Refactor</strong> menu on the <code translate="no" dir="ltr">Text</code> widget. However, this time you aren't going to extract the widget.</p> <p>Instead, select <strong>Wrap with Padding</strong>. This creates a new parent widget around the <code translate="no" dir="ltr">Text</code> widget called <code translate="no" dir="ltr">Padding</code>. After saving, you'll see that the random word already has more breathing room.</p> <devsite-youtube video-id="zPklkjwUsFc"></devsite-youtube> <p>Increase the padding from the default value of <code translate="no" dir="ltr">8.0</code>. For example, use something like <code translate="no" dir="ltr">20</code> for roomier padding.</p> <aside class="special"><p><strong>Note</strong>: Flutter uses Composition over Inheritance whenever it can. Here, instead of padding being an <em>attribute</em> of <code translate="no" dir="ltr">Text</code>, it's a widget!</p> <p>This way, widgets can focus on their single responsibility, and you, the developer, have total freedom in how to compose your UI. For example, you can use the <code translate="no" dir="ltr">Padding</code> widget to pad text, images, buttons, your own custom widgets, or the whole app. The widget doesn't care what it's wrapping.</p> </aside> <p>Next, go one level higher. Place your cursor on the <code translate="no" dir="ltr">Padding</code> widget, pull up the <strong>Refactor</strong> menu, and select <strong>Wrap with widget...</strong>.</p> <p>This allows you to specify the parent widget. Type "Card" and press <strong>Enter</strong>.</p> <devsite-youtube video-id="vUWDPPeCCiE"></devsite-youtube> <p>This wraps the <code translate="no" dir="ltr">Padding</code> widget, and therefore also the <code translate="no" dir="ltr">Text</code>, with a <code translate="no" dir="ltr">Card</code> widget.</p> <p class="image-container"><img alt="6031adbc0a11e16b.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6031adbc0a11e16b_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 is-upgraded id="theme-and-style" data-text="Theme and style" tabindex="-1">Theme and style</h2> <p>To make the card stand out more, paint it with a richer color. And because it's always a good idea to keep a consistent color scheme, use the app's <code translate="no" dir="ltr">Theme</code> to choose the color.</p> <p>Make the following changes to <code translate="no" dir="ltr">BigCard</code>'s <code translate="no" dir="ltr">build()</code> method.</p> <h3 is-upgraded id="libmain.dart_11" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_d_theme/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">);</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Card</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primary</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">And</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">also</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Padding</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">padding</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">20</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>These two new lines do a lot of work:</p> <ul> <li>First, the code requests the app's current theme with <code translate="no" dir="ltr">Theme.of(context)</code>.</li> <li>Then, the code defines the card's color to be the same as the theme's <code translate="no" dir="ltr">colorScheme</code> property. The color scheme contains many colors, and <code translate="no" dir="ltr">primary</code> is the most prominent, defining color of the app.</li> </ul> <p>The card is now painted with the app's primary color:</p> <p class="image-container"><img alt="a136f7682c204ea1.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a136f7682c204ea1_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>You can change this color, and the color scheme of the whole app, by scrolling up to <code translate="no" dir="ltr">MyApp</code> and changing the seed color for the <code translate="no" dir="ltr">ColorScheme</code> there.</p> <aside class="special"><p><strong>Tip</strong>: Flutter's <code translate="no" dir="ltr">Colors</code> class gives you convenient access to a palette of hand-picked colors, such as <code translate="no" dir="ltr">Colors.deepOrange</code> or <code translate="no" dir="ltr">Colors.red</code>. But you can, of course, choose any color. To define pure green with full opacity, for example, use <code translate="no" dir="ltr">Color.fromRGBO(0, 255, 0, 1.0)</code>. If you're a fan of hexadecimal numbers, there's always <code translate="no" dir="ltr">Color(0xFF00FF00)</code>.</p> </aside> <devsite-youtube video-id="RC8mLce-CKU"></devsite-youtube> <p>Notice how the color animates smoothly. This is called an <strong>implicit animation</strong>. Many Flutter widgets will smoothly interpolate between values so that the UI doesn't just "jump" between states.</p> <p>The elevated button below the card also changes color. That's the power of using an app-wide <code translate="no" dir="ltr">Theme</code> as opposed to hard-coding values.</p> <h2 is-upgraded id="texttheme" data-text="TextTheme" tabindex="-1">TextTheme</h2> <p>The card still has a problem: the text is too small and its color is hard to read. To fix this, make the following changes to <code translate="no" dir="ltr">BigCard</code>'s <code translate="no" dir="ltr">build()</code> method.</p> <h3 is-upgraded id="libmain.dart_12" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_e_text_style/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">displayMedium</span><span class="devsite-syntax-o">!.</span><span class="devsite-syntax-n">copyWith</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">onPrimary</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Card</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primary</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Padding</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">padding</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">20</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Change</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>What's behind this change:</p> <ul> <li>By using <code translate="no" dir="ltr">theme.textTheme,</code> you access the app's font theme. This class includes members such as <code translate="no" dir="ltr">bodyMedium</code> (for standard text of medium size), <code translate="no" dir="ltr">caption</code> (for captions of images), or <code translate="no" dir="ltr">headlineLarge</code> (for large headlines).</li> <li>The <code translate="no" dir="ltr">displayMedium</code> property is a large style meant for display text. The word <em>display</em> is used in the typographic sense here, such as in <a href="https://en.wikipedia.org/wiki/Display_typeface" target="_blank">display typeface</a>. The documentation for <code translate="no" dir="ltr">displayMedium</code> says that "display styles are reserved for short, important text"—exactly our use case.</li> <li>The theme's <code translate="no" dir="ltr">displayMedium</code> property could theoretically be <code translate="no" dir="ltr">null</code>. Dart, the programming language in which you're writing this app, is null-safe, so it won't let you call methods of objects that are potentially <code translate="no" dir="ltr">null</code>. In this case, though, you can use the <code translate="no" dir="ltr">!</code> operator ("bang operator") to assure Dart you know what you're doing. (<code translate="no" dir="ltr">displayMedium</code> is definitely <em>not</em> null in this case. The reason we know this is beyond the scope of this codelab, though.)</li> <li>Calling <code translate="no" dir="ltr">copyWith()</code> on <code translate="no" dir="ltr">displayMedium</code> returns a <em>copy</em> of the text style <em>with</em> the changes you define. In this case, you're only changing the text's color.</li> <li>To get the new color, you once again access the app's theme. The color scheme's <code translate="no" dir="ltr">onPrimary</code> property defines a color that is a good fit for use <em>on</em> the app's <em>primary</em> color.</li> </ul> <p>The app should now look something like the following:</p> <p class="image-container"><img alt="2405e9342d28c193.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/2405e9342d28c193.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/2405e9342d28c193_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>If you feel like it, change the card further. Here are some ideas:</p> <ul> <li><code translate="no" dir="ltr">copyWith()</code> lets you change a lot more about the text style than just the color. To get the full list of properties you can change, put your cursor anywhere inside <code translate="no" dir="ltr">copyWith()</code>'s parentheses, and hit <code translate="no" dir="ltr">Ctrl+Shift+Space</code> (Win/Linux) or <code translate="no" dir="ltr">Cmd+Shift+Space</code> (Mac).</li> <li>Similarly, you can change more about the <code translate="no" dir="ltr">Card</code> widget. For example, you can enlarge the card's shadow by increasing the <code translate="no" dir="ltr">elevation</code> parameter's value.</li> <li>Try experimenting with colors. Apart from <code translate="no" dir="ltr">theme.colorScheme.primary</code>, there's also <code translate="no" dir="ltr">.secondary</code>, <code translate="no" dir="ltr">.surface</code>, and a myriad of others. All of these colors have their <code translate="no" dir="ltr">onPrimary</code> equivalents.</li> </ul> <h2 is-upgraded id="improve-accessibility" data-text="Improve accessibility" tabindex="-1">Improve accessibility</h2> <p>Flutter makes apps accessible by default. For example, every Flutter app correctly surfaces all text and interactive elements in the app to screen readers such as TalkBack and VoiceOver.</p> <p class="image-container"><img alt="d1fad7944fb890ea.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d1fad7944fb890ea_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Sometimes, though, some work is required. In the case of this app, the screen reader might have problems pronouncing some generated word pairs. While humans don't have problems identifying the two words in <strong>cheaphead</strong>, a screen reader might pronounce the <strong>ph</strong> in the middle of the word as <strong>f</strong>.</p> <p>A simple solution is to replace <code translate="no" dir="ltr">pair.asLowerCase</code> with <code translate="no" dir="ltr">"${pair.first} ${pair.second}"</code>. The latter uses string interpolation to create a string (such as <code translate="no" dir="ltr">"cheap head"</code>) from the two words contained in <code translate="no" dir="ltr">pair</code>. Using two separate words instead of a compound word makes sure that screen readers identify them appropriately, and provides a better experience to visually impaired users.</p> <p>However, you might want to keep the visual simplicity of <code translate="no" dir="ltr">pair.asLowerCase</code>. Use <code translate="no" dir="ltr">Text</code>'s <code translate="no" dir="ltr">semanticsLabel</code> property to override the visual content of the text widget with a semantic content that is more appropriate for screen readers:</p> <h3 is-upgraded id="libmain.dart_13" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_f_accessibility/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">displayMedium</span><span class="devsite-syntax-o">!.</span><span class="devsite-syntax-n">copyWith</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">onPrimary</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Card</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primary</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Padding</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">padding</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">20</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Make</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">following</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">change</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">semanticsLabel</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s2">"${pair.first} ${pair.second}"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Now, screen readers correctly pronounce each generated word pair, yet the UI stays the same. Try this in action by <a href="https://docs.flutter.dev/development/accessibility-and-localization/accessibility?tab=voiceover#screen-readers" target="_blank">using a screen reader on your device</a>.</p> <aside class="special"><p><strong>Tip</strong>: Flutter has a variety of tools for accessibility, including automated tests and the <code translate="no" dir="ltr">Semantics</code> widget. Learn more on Flutter documentation's <a href="https://docs.flutter.dev/development/accessibility-and-localization/accessibility" target="_blank">Accessibility page</a>.</p> </aside> <h2 is-upgraded id="center-the-ui" data-text="Center the UI" tabindex="-1">Center the UI</h2> <p>Now that the random word pair is presented with enough visual flair, it's time to place it in the center of the app's window/screen.</p> <p>First, remember that <code translate="no" dir="ltr">BigCard</code> is part of a <code translate="no" dir="ltr">Column</code>. By default, columns lump their children to the top, but we can easily override this. Go to <code translate="no" dir="ltr">MyHomePage</code>'s <code translate="no" dir="ltr">build()</code> method, and make the following change:</p> <h3 is-upgraded id="libmain.dart_14" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_g_center_vertical/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisAlignment</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisAlignment</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">center</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'A random AWESOME idea:'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>This centers the children inside the <code translate="no" dir="ltr">Column</code> along its main (vertical) axis.</p> <p class="image-container"><img alt="b555d4c7f5000edf.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/b555d4c7f5000edf_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>The children are already centered along the column's <em>cross</em> axis (in other words, they are already centered horizontally). But the <code translate="no" dir="ltr">Column</code> <em>itself</em> isn't centered inside the <code translate="no" dir="ltr">Scaffold</code>. We can verify this by using the <strong>Widget Inspector</strong>.</p> <devsite-youtube video-id="v0KWdBaoark"></devsite-youtube> <p>The Widget Inspector itself is beyond the scope of this codelab, but you can see that when the <code translate="no" dir="ltr">Column</code> is highlighted, it doesn't take up the whole width of the app. It only takes up as much horizontal space as its children need.</p> <p>You can just center the column itself. Put your cursor onto <code translate="no" dir="ltr">Column</code>, call up the <strong>Refactor</strong> menu (with <code translate="no" dir="ltr">Ctrl+.</code> or <code translate="no" dir="ltr">Cmd+.</code>), and select <strong>Wrap with Center</strong>.</p> <devsite-youtube video-id="9HwsC1EJpHE"></devsite-youtube> <p>The app should now look something like the following:</p> <p class="image-container"><img alt="455688d93c30d154.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/455688d93c30d154.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/455688d93c30d154_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>If you want, you can tweak this some more.</p> <ul> <li>You can remove the <code translate="no" dir="ltr">Text</code> widget above <code translate="no" dir="ltr">BigCard</code>. It could be argued that the descriptive text ("A random AWESOME idea:") isn't needed anymore since the UI makes sense even without it. And it's cleaner that way.</li> <li>You can also add a <code translate="no" dir="ltr">SizedBox(height: 10)</code> widget between <code translate="no" dir="ltr">BigCard</code> and <code translate="no" dir="ltr">ElevatedButton</code>. This way, there's a bit more separation between the two widgets. The <code translate="no" dir="ltr">SizedBox</code> widget just takes space and doesn't render anything by itself. It's commonly used to create visual "gaps".</li> </ul> <p>With the optional changes, <code translate="no" dir="ltr">MyHomePage</code> contains this code:</p> <h3 is-upgraded id="libmain.dart_15" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_05_i_optional_changes/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisAlignment</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisAlignment</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">center</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SizedBox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">height</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">10</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>And the app looks like the following:</p> <p class="image-container"><img alt="3d53d2b071e2f372.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>In the next section, you'll add the ability to favorite (or ‘like') generated words.</p> </google-codelab-step> <google-codelab-step label="Add functionality" duration="10" step="5"> <h2 class="step-title" id="5" data-text="Add functionality" tabindex="-1"> 6. Add functionality </h2> <p>The app works, and occasionally even provides interesting word pairs. But whenever the user clicks <strong>Next</strong>, each word pair disappears forever. It would be better to have a way of "remembering" the best suggestions: such as a ‘Like' button.</p> <p class="image-container"><img alt="e6b01a8c90df8ffa.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 is-upgraded id="add-the-business-logic" data-text="Add the business logic" tabindex="-1">Add the business logic</h2> <p>Scroll to <code translate="no" dir="ltr">MyAppState</code> and add the following code:</p> <h3 is-upgraded id="libmain.dart_16" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_06_a_business_logic/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyAppState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ChangeNotifier</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">random</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">void</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">WordPair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">random</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">notifyListeners</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">the</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">code</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">below</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><<span class="devsite-syntax-n">WordPair</span>><span class="devsite-syntax-p">[];</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">void</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">toggleFavorite</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">contains</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">))</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">remove</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">add</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">notifyListeners</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Examine the changes:</p> <ul> <li>You added a new property to <code translate="no" dir="ltr">MyAppState</code> called <code translate="no" dir="ltr">favorites</code>. This property is initialized with an empty list: <code translate="no" dir="ltr">[]</code>.</li> <li>You also specified that the list can only ever contain word pairs: <code translate="no" dir="ltr"><WordPair>[]</code>, using <a href="https://dart.dev/guides/language/language-tour#generics" target="_blank">generics</a>. This helps make your app more robust—Dart refuses to even <em>run</em> your app if you try to add anything other than <code translate="no" dir="ltr">WordPair</code> to it. In turn, you can use the <code translate="no" dir="ltr">favorites</code> list knowing that there can never be any unwanted objects (like <code translate="no" dir="ltr">null</code>) hiding in there.</li> </ul> <aside class="warning"><p><strong>Note</strong>: Dart has collection types other than <code translate="no" dir="ltr">List</code> (expressed with <code translate="no" dir="ltr">[]</code>). You could argue that a <code translate="no" dir="ltr">Set</code> (expressed with <code translate="no" dir="ltr">{}</code>) would make more sense for a collection of favorites. To make this codelab as straightforward as possible, we're sticking with a list. But if you want, you can use a <code translate="no" dir="ltr">Set</code> instead. The code wouldn't change much.</p> </aside> <ul> <li>You also added a new method, <code translate="no" dir="ltr">toggleFavorite()</code>, which either removes the current word pair from the list of favorites (if it's already there), or adds it (if it isn't there yet). In either case, the code calls <code translate="no" dir="ltr">notifyListeners();</code> afterwards.</li> </ul> <h2 is-upgraded id="add-the-button" data-text="Add the button" tabindex="-1">Add the button</h2> <p>With the "business logic" out of the way, it's time to work on the user interface again. Placing the ‘Like' button to the left of the ‘Next' button requires a <code translate="no" dir="ltr">Row</code>. The <code translate="no" dir="ltr">Row</code> widget is the horizontal equivalent of <code translate="no" dir="ltr">Column</code>, which you saw earlier.</p> <p>First, wrap the existing button in a <code translate="no" dir="ltr">Row</code>. Go to <code translate="no" dir="ltr">MyHomePage</code>'s <code translate="no" dir="ltr">build()</code> method, put your cursor on the <code translate="no" dir="ltr">ElevatedButton</code>, call up the <strong>Refactor</strong> menu with <code translate="no" dir="ltr">Ctrl+.</code> or <code translate="no" dir="ltr">Cmd+.</code>, and select <strong>Wrap with Row</strong>.</p> <devsite-youtube video-id="_G0mTrAAnrI"></devsite-youtube> <p>When you save, you'll notice that <code translate="no" dir="ltr">Row</code> acts similarly to <code translate="no" dir="ltr">Column</code>—by default, it lumps its children to the left. (<code translate="no" dir="ltr">Column</code> lumped its children to the top.) To fix this, you could use the same approach as before, but with <code translate="no" dir="ltr">mainAxisAlignment</code>. However, for didactic (learning) purposes, use <code translate="no" dir="ltr">mainAxisSize</code>. This tells <code translate="no" dir="ltr">Row</code> not to take all available horizontal space.</p> <p>Make the following change:</p> <h3 is-upgraded id="libmain.dart_17" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_06_b_add_row/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisAlignment</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisAlignment</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">center</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SizedBox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">height</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">10</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisSize</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisSize</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">min</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>The UI is back to where it was before.</p> <p class="image-container"><img alt="3d53d2b071e2f372.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/3d53d2b071e2f372_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Next, add the <strong>Like</strong> button and connect it to <code translate="no" dir="ltr">toggleFavorite()</code>. For a challenge, first try to do this by yourself, without looking at the code block below.</p> <p class="image-container"><img alt="e6b01a8c90df8ffa.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e6b01a8c90df8ffa_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>It's okay if you don't do it exactly the same way as it's done below. In fact, don't worry about the heart icon unless you really want a major challenge.</p> <p>It's also completely okay to fail—this is your first hour with Flutter, after all.</p> <p class="image-container"><img alt="252f7c4a212c94d2.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Here's one way to add the second button to <code translate="no" dir="ltr">MyHomePage</code>. This time, use the <code translate="no" dir="ltr">ElevatedButton.icon()</code> constructor to create a button with an icon. And at the top of the <code translate="no" dir="ltr">build</code> method, choose the appropriate icon depending on whether the current word pair is already in favorites. Also, note the use of <code translate="no" dir="ltr">SizedBox</code> again, to keep the two buttons a bit apart.</p> <h3 is-upgraded id="libmain.dart_18" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_06_c_add_like_button/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">IconData</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">contains</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">))</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite_border</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisAlignment</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisAlignment</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">center</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SizedBox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">height</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">10</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisSize</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisSize</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">min</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">And</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">toggleFavorite</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Like'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SizedBox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">width</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">10</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>The app should look as follows:</p> <devsite-youtube video-id="6c58yWuCrAk"></devsite-youtube> <p>Unfortunately, the user can't <em>see</em> the favorites. It's time to add a whole separate screen to our app. See you in the next section!</p> </google-codelab-step> <google-codelab-step label="Add navigation rail" duration="20" step="6"> <h2 class="step-title" id="6" data-text="Add navigation rail" tabindex="-1"> 7. Add navigation rail </h2> <p>Most apps can't fit everything into a single screen. This particular app probably could, but for didactic purposes, you are going to create a separate screen for the user's favorites. To switch between the two screens, you are going to implement your first <code translate="no" dir="ltr">StatefulWidget</code>.</p> <p class="image-container"><img alt="f62c54f5401a187.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/f62c54f5401a187.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f62c54f5401a187_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>To get to the meat of this step as soon as possible, split <code translate="no" dir="ltr">MyHomePage</code> into 2 separate widgets.</p> <p>Select all of <code translate="no" dir="ltr">MyHomePage</code>, delete it, and replace with the following code:</p> <h3 is-upgraded id="libmain.dart_19" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_07_a_split_my_home_page/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MyHomePage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SafeArea</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRail</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">extended</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">false</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">destinations</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Home'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Favorites'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onDestinationSelected</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">print</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'selected: $value'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Expanded</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primaryContainer</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">GeneratorPage</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">GeneratorPage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">current</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">IconData</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">contains</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">))</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite_border</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisAlignment</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisAlignment</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">center</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BigCard</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SizedBox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">height</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">10</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">mainAxisSize</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">MainAxisSize</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">min</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">toggleFavorite</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Like'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SizedBox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">width</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">10</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ElevatedButton</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onPressed</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getNext</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Next'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>When saved, you'll see that the visual side of the UI is ready—but it doesn't work. Clicking ♥︎ (the heart) in the navigation rail does nothing.</p> <p class="image-container"><img alt="388bc25fe198c54a.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/388bc25fe198c54a_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Examine the changes.</p> <ul> <li>First, notice that the entire contents of <code translate="no" dir="ltr">MyHomePage</code> is extracted into a new widget, <code translate="no" dir="ltr">GeneratorPage</code>. The only part of the old <code translate="no" dir="ltr">MyHomePage</code> widget that didn't get extracted is <code translate="no" dir="ltr">Scaffold</code>.</li> <li>The new <code translate="no" dir="ltr">MyHomePage</code> contains a <code translate="no" dir="ltr">Row</code> with two children. The first widget is <code translate="no" dir="ltr">SafeArea</code>, and the second is an <code translate="no" dir="ltr">Expanded</code> widget.</li> <li>The <code translate="no" dir="ltr">SafeArea</code> ensures that its child is not obscured by a hardware notch or a status bar. In this app, the widget wraps around <code translate="no" dir="ltr">NavigationRail</code> to prevent the navigation buttons from being obscured by a mobile status bar, for example.</li> <li>You can change the <code translate="no" dir="ltr">extended: false</code> line in NavigationRail to <code translate="no" dir="ltr">true</code>. This shows the labels next to the icons. In a future step, you will learn how to do this automatically when the app has enough horizontal space.</li> <li>The navigation rail has two destinations (<em>Home</em> and <em>Favorites</em>), with their respective icons and labels. It also defines the current <code translate="no" dir="ltr">selectedIndex</code>. A selected index of zero selects the first destination, a selected index of one selects the second destination, and so on. For now, it's hard coded to zero.</li> <li>The navigation rail also defines what happens when the user selects one of the destinations with <code translate="no" dir="ltr">onDestinationSelected</code>. Right now, the app merely outputs the requested index value with <code translate="no" dir="ltr">print()</code>.</li> <li>The second child of the <code translate="no" dir="ltr">Row</code> is the <code translate="no" dir="ltr">Expanded</code> widget. Expanded widgets are extremely useful in rows and columns—they let you express layouts where some children take only as much space as they need (<code translate="no" dir="ltr">SafeArea</code>, in this case) and other widgets should take as much of the remaining room as possible (<code translate="no" dir="ltr">Expanded</code>, in this case). One way to think about <code translate="no" dir="ltr">Expanded</code> widgets is that they are "greedy". If you want to get a better feel of the role of this widget, try wrapping the <code translate="no" dir="ltr">SafeArea</code> widget with another <code translate="no" dir="ltr">Expanded</code>. The resulting layout looks something like this:</li> </ul> <p class="image-container"><img alt="6bbda6c1835a1ae.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/6bbda6c1835a1ae_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <ul> <li>Two <code translate="no" dir="ltr">Expanded</code> widgets split all the available horizontal space between themselves, even though the navigation rail only really needed a little slice on the left.</li> <li>Inside the <code translate="no" dir="ltr">Expanded</code> widget, there's a colored <code translate="no" dir="ltr">Container</code>, and inside the container, the <code translate="no" dir="ltr">GeneratorPage</code>.</li> </ul> <h2 is-upgraded id="stateless-versus-stateful-widgets" data-text="Stateless versus stateful widgets" tabindex="-1">Stateless versus stateful widgets</h2> <p>Until now, <code translate="no" dir="ltr">MyAppState</code> covered all your state needs. That's why all the widgets you have written so far are state<strong>less</strong>. They don't contain any mutable state of their own. None of the widgets can change <em>itself</em>—they must go through <code translate="no" dir="ltr">MyAppState</code>.</p> <p>This is about to change.</p> <p>You need some way to hold the value of the navigation rail's <code translate="no" dir="ltr">selectedIndex</code>. You also want to be able to change this value from within the <code translate="no" dir="ltr">onDestinationSelected</code> callback.</p> <p>You <em>could</em> add <code translate="no" dir="ltr">selectedIndex</code> as yet another property of <code translate="no" dir="ltr">MyAppState</code>. And it would work. But you can imagine that the app state would quickly grow beyond reason if every widget stored its values in it.</p> <p class="image-container"><img alt="e52d9c0937cc0823.jpeg" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823.jpeg" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_36.jpeg 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_48.jpeg 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_72.jpeg 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_96.jpeg 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_480.jpeg 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_720.jpeg 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_856.jpeg 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_960.jpeg 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_1440.jpeg 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_1920.jpeg 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/e52d9c0937cc0823_2880.jpeg 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Some state is only relevant to a single widget, so it should stay with that widget.</p> <p>Enter the <code translate="no" dir="ltr">StatefulWidget</code>, a type of widget that has <code translate="no" dir="ltr">State</code>. First, convert <code translate="no" dir="ltr">MyHomePage</code> to a stateful widget.</p> <p>Place your cursor on the first line of <code translate="no" dir="ltr">MyHomePage</code> (the one that starts with <code translate="no" dir="ltr">class MyHomePage...</code>), and call up the <strong>Refactor</strong> menu using <code translate="no" dir="ltr">Ctrl+.</code> or <code translate="no" dir="ltr">Cmd+.</code>. Then, select <strong>Convert to StatefulWidget</strong>.</p> <devsite-youtube video-id="Cl0RQJXxNPY"></devsite-youtube> <p>The IDE creates a new class for you, <code translate="no" dir="ltr">_MyHomePageState</code>. This class extends <code translate="no" dir="ltr">State</code>, and can therefore manage its own values. (It can change <em>itself</em>.) Also notice that the <code translate="no" dir="ltr">build</code> method from the old, stateless widget has moved to the <code translate="no" dir="ltr">_MyHomePageState</code> (instead of staying in the widget). It was moved verbatim—nothing inside the <code translate="no" dir="ltr">build</code> method changed. It now merely lives somewhere else.</p> <aside class="warning"><p>The underscore (<code translate="no" dir="ltr">_</code>) at the start of <code translate="no" dir="ltr">_MyHomePageState</code> makes that class private and is enforced by the compiler. If you want to know more about privacy in Dart, and other topics, read the <a href="https://dart.dev/language/libraries" target="_blank">Language Tour</a>.</p> </aside> <h2 is-upgraded id="setstate" data-text="setState" tabindex="-1">setState</h2> <p>The new stateful widget only needs to track one variable: <code translate="no" dir="ltr">selectedIndex</code>. Make the following 3 changes to <code translate="no" dir="ltr">_MyHomePageState</code>:</p> <h3 is-upgraded id="libmain.dart_20" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_07_c_add_selectedindex/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_MyHomePageState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">State<MyHomePage></span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">;</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">property</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SafeArea</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRail</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">extended</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">false</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">destinations</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Home'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Favorites'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Change</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onDestinationSelected</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">↓</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Replace</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">print</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">with</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">setState</span><span class="devsite-syntax-p">(()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Expanded</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primaryContainer</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">GeneratorPage</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Examine the changes:</p> <ol type="1"> <li>You introduce a new variable, <code translate="no" dir="ltr">selectedIndex</code>, and initialize it to <code translate="no" dir="ltr">0</code>.</li> <li>You use this new variable in the <code translate="no" dir="ltr">NavigationRail</code> definition instead of the hard-coded <code translate="no" dir="ltr">0</code> that was there until now.</li> <li>When the <code translate="no" dir="ltr">onDestinationSelected</code> callback is called, instead of merely printing the new value to console, you assign it to <code translate="no" dir="ltr">selectedIndex</code> inside a <code translate="no" dir="ltr">setState()</code> call. This call is similar to the <code translate="no" dir="ltr">notifyListeners()</code> method used previously—it makes sure that the UI updates.</li> </ol> <devsite-youtube video-id="H3lyeYb-XEI"></devsite-youtube> <p>The navigation rail now responds to user interaction. But the expanded area on the right stays the same. That's because the code isn't using <code translate="no" dir="ltr">selectedIndex</code> to determine what screen displays.</p> <h2 is-upgraded id="use-selectedindex" data-text="Use selectedIndex" tabindex="-1">Use selectedIndex</h2> <p>Place the following code at the top of <code translate="no" dir="ltr">_MyHomePageState</code>'s <code translate="no" dir="ltr">build</code> method, just before <code translate="no" dir="ltr">return Scaffold</code>:</p> <h3 is-upgraded id="libmain.dart_21" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_07_d_use_selectedindex/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Carbon"><code translate="no" dir="ltr"><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-nx">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">page</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-nx">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">selectedIndex</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">page</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">GeneratorPage</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">break</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">1</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">page</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">Placeholder</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">break</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">default</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">UnimplementedError</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-err">'</span><span class="devsite-syntax-nx">no</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">$</span><span class="devsite-syntax-nx">selectedIndex</span><span class="devsite-syntax-err">'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-c1">// ...</span> </code></pre></devsite-code> <p>Examine this piece of code:</p> <ol type="1"> <li>The code declares a new variable, <code translate="no" dir="ltr">page</code>, of the type <code translate="no" dir="ltr">Widget</code>.</li> <li>Then, a switch statement assigns a screen to <code translate="no" dir="ltr">page</code>, according to the current value in <code translate="no" dir="ltr">selectedIndex</code>.</li> <li>Since there's no <code translate="no" dir="ltr">FavoritesPage</code> yet, use <code translate="no" dir="ltr">Placeholder</code>; a handy widget that draws a crossed rectangle wherever you place it, marking that part of the UI as unfinished.</li> </ol> <p class="image-container"><img alt="5685cf886047f6ec.png" style="width: 287.50px" src="/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/5685cf886047f6ec_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <ol type="1" start="4"> <li>Applying the <a href="https://en.wikipedia.org/wiki/Fail-fast" target="_blank">fail-fast principle</a>, the switch statement also makes sure to throw an error if <code translate="no" dir="ltr">selectedIndex</code> is neither 0 or 1. This helps prevent bugs down the line. If you ever add a new destination to the navigation rail and forget to update this code, the program crashes in development (as opposed to letting you guess why things don't work, or letting you publish a buggy code into production).</li> </ol> <p>Now that <code translate="no" dir="ltr">page</code> contains the widget you want to show on the right, you can probably guess what other change is needed.</p> <p>Here's <code translate="no" dir="ltr">_MyHomePageState</code> after that single remaining change:</p> <h3 is-upgraded id="libmain.dart_22" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_07_d_use_selectedindex/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_MyHomePageState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">State<MyHomePage></span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">GeneratorPage</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">break</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">1</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Placeholder</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">break</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">default</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">UnimplementedError</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'no widget for $selectedIndex'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SafeArea</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRail</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">extended</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-bp">false</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">destinations</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Home'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Favorites'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onDestinationSelected</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">setState</span><span class="devsite-syntax-p">(()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Expanded</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primaryContainer</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>The app now switches between our <code translate="no" dir="ltr">GeneratorPage</code> and the placeholder that will soon become the <strong>Favorites</strong> page.</p> <devsite-youtube video-id="QM20fLcSYjs"></devsite-youtube> <h2 is-upgraded id="responsiveness" data-text="Responsiveness" tabindex="-1">Responsiveness</h2> <p>Next, make the navigation rail responsive. That is to say, make it automatically show the labels (using <code translate="no" dir="ltr">extended: true</code>) when there's enough room for them.</p> <p class="image-container"><img alt="a8873894c32e0d0b.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/a8873894c32e0d0b_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>Flutter provides several widgets that help you make your apps <em>automatically</em> responsive. For example, <code translate="no" dir="ltr">Wrap</code> is a widget similar to <code translate="no" dir="ltr">Row</code> or <code translate="no" dir="ltr">Column</code> that automatically wraps children to the next "line" (called "run") when there isn't enough vertical or horizontal space. There's <code translate="no" dir="ltr">FittedBox</code>, a widget that automatically fits its child into available space according to your specifications.</p> <p>But <code translate="no" dir="ltr">NavigationRail</code> doesn't <em>automatically</em> show labels when there's enough space because it can't know what <em>is</em> enough space in every context. It's up to you, the developer, to make that call.</p> <p>Say you decide to show labels only if <code translate="no" dir="ltr">MyHomePage</code> is at least 600 pixels wide.</p> <aside class="warning"><p><strong>Note:</strong> Flutter works with logical pixels as a unit of length. They are also sometimes called <strong>device-independent pixels</strong>. A padding of 8 pixels is visually the same regardless of whether the app is running on an old low-res phone or a newer ‘retina' device. There are roughly 38 logical pixels per centimeter, or about 96 logical pixels per inch, of the physical display.</p> </aside> <p>The widget to use, in this case, is <code translate="no" dir="ltr">LayoutBuilder</code>. It lets you change your widget tree depending on how much available space you have.</p> <p>Once again, use Flutter's <strong>Refactor</strong> menu in VS Code to make the required changes. This time, though, it's a little more complicated:</p> <ol type="1"> <li>Inside <code translate="no" dir="ltr">_MyHomePageState</code>'s <code translate="no" dir="ltr">build</code> method, put your cursor on <code translate="no" dir="ltr">Scaffold</code>.</li> <li>Call up the <strong>Refactor</strong> menu with <code translate="no" dir="ltr">Ctrl+.</code> (Windows/Linux) or <code translate="no" dir="ltr">Cmd+.</code> (Mac).</li> <li>Select <strong>Wrap with Builder</strong> and press <strong>Enter</strong>.</li> <li>Modify the name of the newly added <code translate="no" dir="ltr">Builder</code> to <code translate="no" dir="ltr">LayoutBuilder</code>.</li> <li>Modify the callback parameter list from <code translate="no" dir="ltr">(context)</code> to <code translate="no" dir="ltr">(context, constraints)</code>.</li> </ol> <devsite-youtube video-id="GAST9cQDYsw"></devsite-youtube> <p><code translate="no" dir="ltr">LayoutBuilder</code>'s <code translate="no" dir="ltr">builder</code> callback is called every time the constraints change. This happens when, for example:</p> <ul> <li>The user resizes the app's window</li> <li>The user rotates their phone from portrait mode to landscape mode, or back</li> <li>Some widget next to <code translate="no" dir="ltr">MyHomePage</code> grows in size, making <code translate="no" dir="ltr">MyHomePage</code>'s constraints smaller</li> <li>And so on</li> </ul> <p>Now your code can decide whether to show the label by querying the current <code translate="no" dir="ltr">constraints</code>. Make the following single-line change to <code translate="no" dir="ltr">_MyHomePageState</code>'s <code translate="no" dir="ltr">build</code> method:</p> <h3 is-upgraded id="libmain.dart_23" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_07_e_add_layout_builder/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_MyHomePageState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">State<MyHomePage></span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">0</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">GeneratorPage</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">break</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">1</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Placeholder</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">break</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">default</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">UnimplementedError</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'no widget for $selectedIndex'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">LayoutBuilder</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">builder</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">constraints</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">SafeArea</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRail</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">extended</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">constraints</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">maxWidth</span><span class="devsite-syntax-w"> </span>><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-mi">600</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">←</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">destinations</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Home'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">NavigationRailDestination</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">icon</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">label</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Favorites'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onDestinationSelected</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">setState</span><span class="devsite-syntax-p">(()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">selectedIndex</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Expanded</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">color</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">colorScheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">primaryContainer</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">page</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> </code></pre></devsite-code> <p>Now, your app responds to its environment, such as screen size, orientation, and platform! In other words, it's responsive!.</p> <devsite-youtube video-id="PjgELjvS6u8"></devsite-youtube> <p>The only work that remains is to replace that <code translate="no" dir="ltr">Placeholder</code> with an actual <strong>Favorites</strong> screen. That's covered in the next section.</p> </google-codelab-step> <google-codelab-step label="Add a new page" duration="10" step="7"> <h2 class="step-title" id="7" data-text="Add a new page" tabindex="-1"> 8. Add a new page </h2> <p>Remember the <code translate="no" dir="ltr">Placeholder</code> widget we used instead of the <strong>Favorites</strong> page?</p> <devsite-youtube video-id="QM20fLcSYjs"></devsite-youtube> <p>It's time to fix this.</p> <p>If you feel adventurous, try to do this step by yourself. Your goal is to show the list of <code translate="no" dir="ltr">favorites</code> in a new stateless widget, <code translate="no" dir="ltr">FavoritesPage</code>, and then show that widget instead of the <code translate="no" dir="ltr">Placeholder</code>.</p> <p>Here are a few pointers:</p> <ul> <li>When you want a <code translate="no" dir="ltr">Column</code> that scrolls, use the <code translate="no" dir="ltr">ListView</code> widget.</li> <li>Remember, access the <code translate="no" dir="ltr">MyAppState</code> instance from any widget using <code translate="no" dir="ltr">context.watch<MyAppState>()</code>.</li> <li>If you also want to try a new widget, <code translate="no" dir="ltr">ListTile</code> has properties like <code translate="no" dir="ltr">title</code> (generally for text), <code translate="no" dir="ltr">leading</code> (for icons or avatars) and <code translate="no" dir="ltr">onTap</code> (for interactions). However, you can achieve similar effects with the widgets you already know.</li> <li>Dart allows using <code translate="no" dir="ltr">for</code> loops inside collection literals. For example, if <code translate="no" dir="ltr">messages</code> contains a list of strings, you can have code like the following:</li> </ul> <p class="image-container"><img alt="f0444bba08f205aa.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/f0444bba08f205aa_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>On the other hand, if you're more familiar with functional programming, Dart also lets you write code like <code translate="no" dir="ltr">messages.map((m) => Text(m)).toList()</code>. And, of course, you can always create a list of widgets and imperatively add to it inside the <code translate="no" dir="ltr">build</code> method.</p> <p>The advantage of adding the <strong>Favorites</strong> page yourself is that you learn more by making your own decisions. The disadvantage is that you might run into trouble that you aren't yet able to solve by yourself. Remember: failing is okay, and is one of the most important elements of learning. Nobody expects you to nail Flutter development in your first hour, and neither should you.</p> <p class="image-container"><img alt="252f7c4a212c94d2.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/252f7c4a212c94d2_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>What follows is just <em>one</em> way to implement the favorites page. How it's implemented will (hopefully) inspire you to play with the code—improve the UI and make it your own.</p> <p>Here's the new <code translate="no" dir="ltr">FavoritesPage</code> class:</p> <h3 is-upgraded id="libmain.dart_24" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/namer/step_08/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FavoritesPage</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">watch<MyAppState></span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">isEmpty</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'No favorites yet.'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ListView</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Padding</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">padding</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">20</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'You have '</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'${appState.favorites.length} favorites:'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appState</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorites</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ListTile</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">leading</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Icon</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Icons</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">favorite</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">pair</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">asLowerCase</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>Here's what the widget does:</p> <ul> <li>It gets the current state of the app.</li> <li>If the list of favorites is empty, it shows a centered message: <strong>No favorites yet</strong>*.*</li> <li>Otherwise, it shows a (scrollable) list.</li> <li>The list starts with a summary (for example, <strong><em>You have 5 favorites</em></strong>*.*).</li> <li>The code then iterates through all the favorites, and constructs a <code translate="no" dir="ltr">ListTile</code> widget for each one.</li> </ul> <p>All that remains now is to replace the <code translate="no" dir="ltr">Placeholder</code> widget with a <code translate="no" dir="ltr">FavoritesPage</code>. And voilá!</p> <devsite-youtube video-id="jj5yBVwnEQw"></devsite-youtube> <p>You can get the final code of this app in the <a href="https://github.com/flutter/codelabs/tree/main/namer/step_08" target="_blank">codelab repo</a> on GitHub.</p> </google-codelab-step> <google-codelab-step label="Next steps" duration="0" step="8"> <h2 class="step-title" id="8" data-text="Next steps" tabindex="-1"> 9. Next steps </h2> <p><strong>Congratulations!</strong></p> <p>Look at you! You took a non-functional scaffold with a <code translate="no" dir="ltr">Column</code> and two <code translate="no" dir="ltr">Text</code> widgets, and made it into a responsive, delightful little app.</p> <p class="image-container"><img alt="d6e3d5f736411f13.png" style="width: 624.00px" src="/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13.png" srcset="https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_36.png 36w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_48.png 48w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_72.png 72w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_96.png 96w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_480.png 480w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_720.png 720w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_856.png 856w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_960.png 960w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/flutter-codelab-first/img/d6e3d5f736411f13_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 class="checklist" is-upgraded id="what-weve-covered" data-text="What we've covered" tabindex="-1">What we've covered</h2> <ul class="checklist"> <li>The basics of how Flutter works</li> <li>Creating layouts in Flutter</li> <li>Connecting user interactions (like button presses) to app behavior</li> <li>Keeping your Flutter code organized</li> <li>Making your app responsive</li> <li>Achieving a consistent look & feel of your app</li> </ul> <h2 is-upgraded id="what-next" data-text="What next?" tabindex="-1">What next?</h2> <ul> <li>Experiment more with the app you wrote during this lab.</li> <li>Look at the code of <a href="https://dartpad.dev/?id=e7076b40fb17a0fa899f9f7a154a02e8" target="_blank">this advanced version</a> of the same app, to see how you can add animated lists, gradients, cross-fades, and more.</li> </ul> <devsite-youtube video-id="g7EbCoor-gg"></devsite-youtube> <ul> <li>Follow your learning journey by going to <a href="https://flutter.dev/learn" target="_blank">flutter.dev/learn</a>.</li> </ul> </google-codelab-step> </google-codelab> </div> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],[],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Connect</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//googledevelopers.blogspot.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Blog </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.facebook.com/Google-Developers-967415219957038" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Facebook </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//medium.com/google-developers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Medium </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//twitter.com/googledevs" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Twitter </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.youtube.com/user/GoogleDevelopers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > YouTube </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Programs</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//www.womentechmakers.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Women Techmakers </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/gdg" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Google Developer Groups </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/experts" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Google Developer Experts </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/accelerators" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Accelerators </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/gdsc" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Google Developer Student Clubs </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Developer consoles</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//console.developers.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Google API Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.cloud.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Google Cloud Platform Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//play.google.com/apps/publish" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Google Play Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.firebase.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Firebase Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.actions.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Actions on Google Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//cast.google.com/publish" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 6)" > Cast SDK Developer Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//chrome.google.com/webstore/developer/dashboard" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 7)" > Chrome Web Store Dashboard </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-sites" aria-label="Other Google Developers websites"> <a href="https://developers.google.com/" class="devsite-footer-sites-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Developers Link"> <picture> <img class="devsite-footer-sites-logo" src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup-google-for-developers.svg" loading="lazy" alt="Google Developers"> </picture> </a> <ul class="devsite-footer-sites-list"> <li class="devsite-footer-sites-item"> <a href="//developer.android.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Android Link" > Android </a> </li> <li class="devsite-footer-sites-item"> <a href="//developer.chrome.com/home" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Chrome Link" > Chrome </a> </li> <li class="devsite-footer-sites-item"> <a href="//firebase.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Firebase Link" > Firebase </a> </li> <li class="devsite-footer-sites-item"> <a href="//cloud.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Cloud Platform Link" > Google Cloud Platform </a> </li> <li class="devsite-footer-sites-item"> <a href="//developers.google.com/products" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer All products Link" > All products </a> </li> </ul> </nav> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//developers.google.com/terms/site-terms" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> <li class="devsite-footer-utility-item devsite-footer-utility-button"> <span class="devsite-footer-utility-description">Sign up for the Google Developers newsletter</span> <a class="devsite-footer-utility-link gc-analytics-event" href="//services.google.com/fb/forms/googledevelopersnewsletter/?utm_medium=referral&utm_source=google-products&utm_team=googledevs&utm_campaign=201611-newsletter-launch" data-category="Site-Wide Custom Events" data-label="Footer Subscribe link" > Subscribe </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[]</script> <script type="application/json" tag-management>{"at": "True", "ga4": [], "ga4p": [], "gtm": [], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "codelab", "projectName": null, "signedIn": "False", "tenant": "codelabs", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="PqRr29CDP4Wx5lCOfnnDPzxZqlhwas"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/js/app_loader.js', '[17,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs","https://codelabs-dot-devsite-v2-prod.appspot.com",1,null,["/_pwa/codelabs/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/favicon.png","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup.svg","https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,116,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyAP-jjEJBzmIyKR4F-3XITp8yM9T1gEEI8","AIzaSyB6xiKGDR5O3Ak2okS4rLkauxGUG7XP0hg","codelabs.developers.google.com","AIzaSyAQk0fBONSGUqCNznf6Krs82Ap1-NV6J4o","AIzaSyCCxcqdrZ_7QMeLCRY20bh_SXdAYqy70KY",null,null,null,["Profiles__enable_complete_playlist_endpoint","MiscFeatureFlags__developers_footer_image","Profiles__enable_awarding_url","MiscFeatureFlags__enable_explain_this_code","Profiles__enable_page_saving","DevPro__enable_developer_subscriptions","Cloud__enable_cloud_dlp_service","TpcFeatures__enable_mirror_tenant_redirects","Cloud__enable_legacy_calculator_redirect","Experiments__reqs_query_experiments","Cloud__enable_cloud_shell","Profiles__enable_release_notes_notifications","Search__enable_page_map","EngEduTelemetry__enable_engedu_telemetry","TpcFeatures__enable_required_headers","Cloud__enable_cloudx_ping","Search__enable_dynamic_content_confidential_banner","Cloud__enable_free_trial_server_call","Profiles__enable_completecodelab_endpoint","CloudShell__cloud_shell_button","DevPro__enable_cloud_innovators_plus","Concierge__enable_pushui","Analytics__enable_clearcut_logging","Cloud__enable_cloud_shell_fte_user_flow","Cloud__enable_cloud_facet_chat","MiscFeatureFlags__emergency_css","Cloud__enable_llm_concierge_chat","MiscFeatureFlags__enable_firebase_utm","MiscFeatureFlags__enable_view_transitions","Cloud__enable_cloudx_experiment_ids","Profiles__enable_dashboard_curated_recommendations","Search__enable_suggestions_from_borg","BookNav__enable_tenant_cache_key","Search__enable_ai_eligibility_checks","Profiles__enable_public_developer_profiles","CloudShell__cloud_code_overflow_menu","Profiles__enable_recognition_badges","MiscFeatureFlags__developers_footer_dark_image","MiscFeatureFlags__enable_variable_operator","Profiles__enable_profile_collections","Profiles__require_profile_eligibility_for_signin","Profiles__enable_developer_profiles_callout","MiscFeatureFlags__enable_project_variables"],null,null,"AIzaSyBLEMok-5suZ67qRPzx0qUtbnLmyT_kCVE","https://developerscontentserving-pa.clients6.google.com","AIzaSyCM4QpTRSqP5qI4Dvjt4OAScIN8sOUlO-k","https://developerscontentsearch-pa.clients6.google.com",1,4,null,"https://developerprofiles-pa.clients6.google.com",[17,"codelabs","Google Codelabs","codelabs.developers.google.com",null,"codelabs-dot-devsite-v2-prod.appspot.com",null,null,[null,1,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],null,null,null,null,[1]],null,[33,null,null,null,null,null,"/images/lockup.svg",null,null,null,null,1,1,null,null,null,null,null,null,null,null,1,null,null,null,null,[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[6,1,14,15,20,22,23,29,32,36],null,[[],[1,1]],[[null,null,null,null,null,null,null,null,null,null,null,null,1]],null,4],null,"pk_live_5170syrHvgGVmSx9sBrnWtA5luvk9BwnVcvIi7HizpwauFG96WedXsuXh790rtij9AmGllqPtMLfhe2RSwD6Pn38V00uBCydV4m"]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>