CINXE.COM
Flutter for UIKit developers | Flutter
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Flutter for UIKit developers | Flutter</title><link rel="icon" href="/assets/images/branding/flutter/icon/64.png" eleventy:ignore><link rel="apple-touch-icon" href="/assets/images/branding/flutter/logo/flutter-logomark-320px.png" eleventy:ignore><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#ffffff"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><meta name="google-site-verification" content="HFqxhSbf9YA_0rBglNLzDiWnrHiK_w4cqDh2YD2GEY4"><script>!function(e,t,a,n){e[n]=e[n]||[],e[n].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var g=t.getElementsByTagName(a)[0],m=t.createElement(a);m.async=!0,m.src="https://www.googletagmanager.com/gtm.js?id=GTM-ND4LWWZ",g.parentNode.insertBefore(m,g)}(window,document,"script","dataLayer")</script><script>!function(e,a,t,n,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=a.createElement(t),s=a.getElementsByTagName(t)[0],o.async=1,o.src="//www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga"),ga("create","UA-67589403-1","auto"),ga("send","pageview")</script><meta name="description" content="Learn how to apply iOS and UIKit developer knowledge when building Flutter apps."><meta name="twitter:card" content="summary_large_image"><meta name="twitter:site" content="@flutterdev"><meta property="og:title" content="Flutter for UIKit developers"><meta property="og:url" content="https://docs.flutter.dev/get-started/flutter-for/uikit-devs"><meta property="og:description" content="Learn how to apply iOS and UIKit developer knowledge when building Flutter apps."><meta property="og:image" content="https://docs.flutter.dev/assets/images/flutter-logo-sharing.png" eleventy:ignore><link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" rel="stylesheet"><script>window.__CALLBACKS=[]</script><link rel="stylesheet" href="/assets/css/main.css"></head><body><a href="#site-content-title" id="skip">Skip to main content</a><section id="cookie-notice"><div class="container"><p>docs.flutter.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic. <a href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">Learn more</a>.</p><button id="cookie-consent" class="btn btn-primary">OK, got it</button></div></section><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-ND4LWWZ" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="overlay-under-drawer"></div><header class="site-header"><nav class="navbar navbar-expand-md justify-content-start justify-content-md-between"><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><i class="material-symbols">menu</i></button> <a class="navbar-brand" href="/"><img src="/assets/images/branding/flutter/logo+text/horizontal/default.svg" alt="Flutter logo" height="37" width="129" class="align-middle"></a><div id="navbarSupportedContent" class="collapse navbar-collapse flex-grow-0"><div class="site-header__sheet-bg" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"></div><div class="site-header__sheet"><ul class="navbar-nav"><div class="site-sidebar site-sidebar--header d-md-none"><ul class="nav flex-column"><li class="nav-header">Get started</li><li class="nav-item"><a class="nav-link" href="/get-started/install">Set up Flutter</a></li><li class="nav-item"><a class="nav-link active collapsible" data-toggle="collapse" href="#header-sidenav-3" role="button" aria-expanded="true" aria-controls="header-sidenav-3">Learn Flutter</a><ul class="nav flex-column flex-nowrap collapse show" id="header-sidenav-3"><li class="nav-item"><a class="nav-link" href="/get-started/learn-flutter">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/get-started/codelab">Write your first app</a></li><li class="nav-item"><a class="nav-link collapsible" data-toggle="collapse" data-target="#header-sidenav-3-3" href="#header-sidenav-3-3" role="button" aria-expanded="true" aria-controls="header-sidenav-3-3">Learn the fundamentals</a><ul class="nav flex-column flex-nowrap collapse show" id="header-sidenav-3-3"><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/dart">Intro to Dart</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/widgets">Widgets</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/layout">Layout</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/state-management">State management</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/user-input">Handling user input</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/networking">Networking and data</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/local-caching">Local data and caching</a></li></ul></li><li class="nav-item"><a class="nav-link active collapsible" data-toggle="collapse" data-target="#header-sidenav-3-4" href="/get-started/flutter-for" role="button" aria-expanded="true" aria-controls="header-sidenav-3-4">From another platform?</a><ul class="nav flex-column flex-nowrap collapse show" id="header-sidenav-3-4"><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/android-devs">Flutter for Android devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/swiftui-devs">Flutter for SwiftUI devs</a></li><li class="nav-item"><a class="nav-link active" href="/get-started/flutter-for/uikit-devs">Flutter for UIKit devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/react-native-devs">Flutter for React Native devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/web-devs">Flutter for web devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/xamarin-forms-devs">Flutter for Xamarin.Forms devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/declarative">Introduction to declarative UI</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/dart-swift-concurrency">Flutter versus Swift concurrency</a></li></ul></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/codelabs">Codelabs</a></li><li class="nav-item"><a class="nav-link" href="/cookbook">Cookbook</a></li><li class="nav-item"><a class="nav-link" href="https://flutter.github.io/samples/" target="_blank" rel="noopener">Demos and samples</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-4" role="button" aria-expanded="false" aria-controls="header-sidenav-4">Stay up to date</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-4"><li class="nav-item"><a class="nav-link" href="/release/upgrade">Upgrade</a></li><li class="nav-item"><a class="nav-link" href="/release/archive">SDK archive</a></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/release/whats-new">What's new</a></li><li class="nav-item"><a class="nav-link" href="/release/release-notes">Release notes</a></li><li class="nav-item"><a class="nav-link" href="/release/breaking-changes">Breaking changes</a></li><li class="nav-item"><a class="nav-link" href="/release/compatibility-policy">Compatibility policy</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-5" role="button" aria-expanded="false" aria-controls="header-sidenav-5">App solutions</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5"><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-1" href="#header-sidenav-5-1" role="button" aria-expanded="false" aria-controls="header-sidenav-5-1">AI</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-1"><li class="nav-item"><a class="nav-link" href="/resources/ai-overview">Overview</a></li><li class="nav-item"><a class="nav-link" href="https://ai.google.dev/gemini-api/docs/get-started/dart" target="_blank" rel="noopener">Get started with the Gemini API</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/google_generative_ai" target="_blank" rel="noopener">Google AI Dart SDK (pub.dev)</a></li><li class="nav-item"><a class="nav-link" href="https://www.youtube.com/watch?v=1AuzJEiHjO4" target="_blank" rel="noopener">Build with Google AI Dart SDK (video)</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-2" href="#header-sidenav-5-2" role="button" aria-expanded="false" aria-controls="header-sidenav-5-2">Firebase & Firestore</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-2"><li class="nav-item"><a class="nav-link" href="/data-and-backend/firebase">Overview</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/flutter" target="_blank" rel="noopener">Discover Firebase for Flutter</a></li><li class="nav-item"><a class="nav-link" href="https://www.youtube.com/watch?v=wUSkeTaBonA" target="_blank" rel="noopener">Get to know Firebase for Flutter</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps" target="_blank" rel="noopener">Add a user authentication flow to a Flutter app using FirebaseUI</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-get-to-know-web" target="_blank" rel="noopener">Get to know Firebase for web</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-3" href="#header-sidenav-5-3" role="button" aria-expanded="false" aria-controls="header-sidenav-5-3">Games</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-3"><li class="nav-item"><a class="nav-link" href="/resources/games-toolkit">Overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/games/achievements-leaderboard">Add achievements and leaderboards</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/build-leaderboards-with-firestore#0" target="_blank" rel="noopener">Build leaderboards with Firestore</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/google-mobile-ads">Add advertising</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/games/firestore-multiplayer">Add multiplayer support</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" target="_blank" rel="noopener">Add in-app purchases</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps" target="_blank" rel="noopener">Add user authentication</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/crashlytics/get-started?platform=flutter" target="_blank" rel="noopener">Debug using Crashlytics</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-flame-brick-breaker" target="_blank" rel="noopener">Intro to Flame with Flutter</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-4" href="#header-sidenav-5-4" role="button" aria-expanded="false" aria-controls="header-sidenav-5-4">Monetization</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-4"><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-4-1" href="#header-sidenav-5-4-1" role="button" aria-expanded="false" aria-controls="header-sidenav-5-4-1">Advertising</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-4-1"><li class="nav-item"><a class="nav-link" href="/resources/ads-overview">Ads overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/google-mobile-ads">Add advertising</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/admob-ads-in-flutter" target="_blank" rel="noopener">Add AdMob ads to your Flutter app</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/admob-inline-ads-in-flutter" target="_blank" rel="noopener">Add an AdMob banner and native inline ads</a></li><li class="nav-item"><a class="nav-link" href="https://developers.google.com/admob/flutter/mediation" target="_blank" rel="noopener">Google AdMob mediation</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/interactive_media_ads" target="_blank" rel="noopener">Interactive Media Ads SDK</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-4-2" href="#header-sidenav-5-4-2" role="button" aria-expanded="false" aria-controls="header-sidenav-5-4-2">In-app purchases</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-4-2"><li class="nav-item"><a class="nav-link" href="/resources/in-app-purchases-overview">In-app purchases overview</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" target="_blank" rel="noopener">Add in-app purchases</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-4-3" href="#header-sidenav-5-4-3" role="button" aria-expanded="false" aria-controls="header-sidenav-5-4-3">Payments</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-4-3"><li class="nav-item"><a class="nav-link" href="/resources/payments-overview">Payments overview</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/pay" target="_blank" rel="noopener">Google pay package</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-5" href="#header-sidenav-5-5" role="button" aria-expanded="false" aria-controls="header-sidenav-5-5">Maps</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-5"><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/google-maps-in-flutter" target="_blank" rel="noopener">Add Google maps to a Flutter app</a></li><li class="nav-item"><a class="nav-link" href="https://developers.google.com/maps/flutter-package" target="_blank" rel="noopener">Google Maps package</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-5-6" href="#header-sidenav-5-6" role="button" aria-expanded="false" aria-controls="header-sidenav-5-6">News</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/resources/news-toolkit">Build a news app</a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-header">User interface</li><li class="nav-item"><a class="nav-link" href="/ui">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/ui/widgets">Widget catalog</a></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-10" role="button" aria-expanded="false" aria-controls="header-sidenav-10">Layout</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-10"><li class="nav-item"><a class="nav-link" href="/ui/layout">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/tutorial">Build a layout</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-10-3" href="/ui/layout/lists" role="button" aria-expanded="false" aria-controls="header-sidenav-10-3">Lists & grids</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-10-3"><li class="nav-item"><a class="nav-link" href="/cookbook/lists/basic-list">Create and use lists</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/horizontal-list">Create a horizontal list</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/grid-lists">Create a grid view</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/mixed-list">Create lists with different types of items</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/spaced-items">Create lists with spaced items</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/long-lists">Work with long lists</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-10-4" href="/ui/layout/scrolling" role="button" aria-expanded="false" aria-controls="header-sidenav-10-4">Scrolling</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-10-4"><li class="nav-item"><a class="nav-link" href="/ui/layout/scrolling">Overview</a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/scrolling/slivers">Use slivers to achieve fancy scrolling</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/floating-app-bar">Place a floating app bar above a list</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/parallax-scrolling">Create a scrolling parallax effect</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-11" role="button" aria-expanded="false" aria-controls="header-sidenav-11">Adaptive & responsive design</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-11"><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive">Overview</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/general">General approach</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/safearea-mediaquery">SafeArea & MediaQuery</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/large-screens">Large screens & foldables</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/input">User input & accessibility</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/capabilities">Capabilities & policies</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/best-practices">Best practices</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/more-info">Additional resources</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-12" role="button" aria-expanded="false" aria-controls="header-sidenav-12">Design & theming</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-12"><li class="nav-item"><a class="nav-link" href="/cookbook/design/themes">Share styles with themes</a></li><li class="nav-item"><a class="nav-link" href="/ui/design/material">Material design</a></li><li class="nav-item"><a class="nav-link" href="/release/breaking-changes/material-3-migration">Migrate to Material 3</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-12-4" href="/ui/design/text" role="button" aria-expanded="false" aria-controls="header-sidenav-12-4">Text</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-12-4"><li class="nav-item"><a class="nav-link" href="/ui/design/text/typography">Fonts & typography</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/fonts">Use a custom font</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/package-fonts">Export fonts from a package</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/google_fonts" target="_blank" rel="noopener">Google Fonts package</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-12-5" href="/ui/design/graphics" role="button" aria-expanded="false" aria-controls="header-sidenav-12-5">Custom graphics</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-12-5"><li class="nav-item"><a class="nav-link" href="/ui/design/graphics/fragment-shaders">Use custom fragment shaders</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-13" role="button" aria-expanded="false" aria-controls="header-sidenav-13">Interactivity</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-13"><li class="nav-item"><a class="nav-link" href="/ui/interactivity">Add interactivity to your app</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-13-2" href="/ui/interactivity/gestures" role="button" aria-expanded="false" aria-controls="header-sidenav-13-2">Gestures</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-13-2"><li class="nav-item"><a class="nav-link" href="/ui/interactivity/gestures">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/handling-taps">Handle taps</a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/gestures/drag-outside">Drag an object outside an app</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/drag-a-widget">Drag a UI element within an app</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/ripples">Add Material touch ripples</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/dismissible">Implement swipe to dismiss</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-13-3" href="/ui/interactivity/input" role="button" aria-expanded="false" aria-controls="header-sidenav-13-3">Input & forms</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-13-3"><li class="nav-item"><a class="nav-link" href="/cookbook/forms/text-input">Create and style a text field</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/retrieve-input">Retrieve the value of a text field</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/text-field-changes">Handle changes to a text field</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/focus">Manage focus in text fields</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/validation">Build a form with validation</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/snackbars">Display a snackbar</a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/actions-and-shortcuts">Implement actions & shortcuts</a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/focus">Manage keyboard focus</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-14" role="button" aria-expanded="false" aria-controls="header-sidenav-14">Assets & media</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-14"><li class="nav-item"><a class="nav-link" href="/ui/assets/assets-and-images">Add assets and images</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/images/network-image">Display images from the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/images/fading-in-images">Fade in images with a placeholder</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/play-video">Play and pause a video</a></li><li class="nav-item"><a class="nav-link" href="/ui/assets/asset-transformation">Transform assets at build time</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-15" role="button" aria-expanded="false" aria-controls="header-sidenav-15">Navigation & routing</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-15"><li class="nav-item"><a class="nav-link" href="/ui/navigation">Overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/tabs">Add tabs to your app</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/navigation-basics">Navigate to a new screen and back</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/passing-data">Send data to a new screen</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/returning-data">Return data from a screen</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/drawer">Add a drawer to a screen</a></li><li class="nav-item"><a class="nav-link" href="/ui/navigation/deep-linking">Set up deep linking</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/set-up-app-links">Set up app links for Android</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/set-up-universal-links">Set up universal links for iOS</a></li><li class="nav-item"><a class="nav-link" href="/ui/navigation/url-strategies">Configure web URL strategies</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-16" role="button" aria-expanded="false" aria-controls="header-sidenav-16">Animations & transitions</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-16"><li class="nav-item"><a class="nav-link" href="/ui/animations">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/tutorial">Tutorial</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/implicit-animations">Implicit animations</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/animated-container">Animate the properties of a container</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/opacity-animation">Fade a widget in and out</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/hero-animations">Hero animations</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/page-route-animation">Animate a page route transition</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/physics-simulation">Animate using a physics simulation</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/staggered-animations">Staggered animations</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/staggered-menu-animation">Create a staggered menu animation</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/overview">API overview</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-17" role="button" aria-expanded="false" aria-controls="header-sidenav-17">Accessibility & internationalization</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-17"><li class="nav-item"><a class="nav-link" href="/ui/accessibility-and-internationalization/accessibility">Accessibility</a></li><li class="nav-item"><a class="nav-link" href="/ui/accessibility-and-internationalization/internationalization">Internationalization</a></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-header">Beyond UI</li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-20" role="button" aria-expanded="false" aria-controls="header-sidenav-20">Data & backend</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-20"><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-20-1" href="/data-and-backend/state-mgmt" role="button" aria-expanded="false" aria-controls="header-sidenav-20-1">State management</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-20-1"><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/intro">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/declarative">Think declaratively</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/ephemeral-vs-app">Ephemeral vs app state</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/simple">Simple app state management</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/options">Options</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-20-2" href="/data-and-backend/networking" role="button" aria-expanded="false" aria-controls="header-sidenav-20-2">Networking & http</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-20-2"><li class="nav-item"><a class="nav-link" href="/data-and-backend/networking">Overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/fetch-data">Fetch data from the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/authenticated-requests">Make authenticated requests</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/send-data">Send data to the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/update-data">Update data over the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/delete-data">Delete data on the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/web-sockets">Communicate with WebSockets</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-20-3" href="/data-and-backend/serialization" role="button" aria-expanded="false" aria-controls="header-sidenav-20-3">Serialization</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-20-3"><li class="nav-item"><a class="nav-link" href="/data-and-backend/serialization/json">JSON serialization</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/background-parsing">Parse JSON in the background</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-20-4" href="/data-and-backend/persistence" role="button" aria-expanded="false" aria-controls="header-sidenav-20-4">Persistence</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-20-4"><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/key-value">Store key-value data on disk</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/reading-writing-files">Read and write files</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/sqlite">Persist data with SQLite</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-20-5" href="/data-and-backend/firebase" role="button" aria-expanded="false" aria-controls="header-sidenav-20-5">Firebase</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-20-5"><li class="nav-item"><a class="nav-link" href="/data-and-backend/firebase">Overview</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/flutter/setup" target="_blank" rel="noopener">Add Firebase to your Flutter app</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/google-apis">Google APIs</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-21" role="button" aria-expanded="false" aria-controls="header-sidenav-21">App architecture</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-21"><li class="nav-item"><a class="nav-link" href="/app-architecture">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/concepts">Architecture concepts</a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/guide">Guide to app architecture</a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/recommendations">Recommendations</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-21-5" href="/cookbook/architecture" role="button" aria-expanded="false" aria-controls="header-sidenav-21-5">Design patterns</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-21-5"><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/optimistic-state">Optimistic state</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/key-value-data">Persistent storage architecture: Key-value data</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/sql">Persistent storage architecture: SQL</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/offline-first">Offline-first</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-22" role="button" aria-expanded="false" aria-controls="header-sidenav-22">Platform integration</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22"><li class="nav-item"><a class="nav-link" href="/reference/supported-platforms">Supported platforms</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/desktop">Build desktop apps with Flutter</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/platform-channels">Write platform-specific code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/platform-adaptations">Automatic platform adaptations</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-22-5" href="/platform-integration/android" role="button" aria-expanded="false" aria-controls="header-sidenav-22-5">Android</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22-5"><li class="nav-item"><a class="nav-link" href="/platform-integration/android/install-android">Add Android as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/splash-screen">Add a splash screen</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/predictive-back">Add predictive back</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/c-interop">Bind to native code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/platform-views">Host a native Android view</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/compose-activity">Launch a Jetpack Compose activity</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/restore-state-android">Restore state on Android</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/chromeos">Target ChromeOS with Android</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-22-6" href="/platform-integration/ios" role="button" aria-expanded="false" aria-controls="header-sidenav-22-6">iOS</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22-6"><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/install-ios">Add iOS as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-latest">Flutter on latest iOS</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/apple-frameworks">Leverage Apple's system libraries</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/launch-screen">Add a launch screen</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-app-clip">Add iOS App Clip support</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/app-extensions">Add iOS app extensions</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/c-interop">Bind to native code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/platform-views">Host a native iOS view</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-debugging">Enable debugging on iOS</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/restore-state-ios">Restore state on iOS</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-22-7" href="/platform-integration/linux" role="button" aria-expanded="false" aria-controls="header-sidenav-22-7">Linux</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22-7"><li class="nav-item"><a class="nav-link" href="/platform-integration/linux/install-linux">Add Linux as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/linux/building">Build a Linux app</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-22-8" href="/platform-integration/macos" role="button" aria-expanded="false" aria-controls="header-sidenav-22-8">macOS</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22-8"><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/install-macos">Add macOS as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/building">Build a macOS app</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/c-interop">Bind to native code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/platform-views">Host a native macOS view</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-22-9" href="/platform-integration/web" role="button" aria-expanded="false" aria-controls="header-sidenav-22-9">Web</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22-9"><li class="nav-item"><a class="nav-link" href="/platform-integration/web/">Web support in Flutter</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/install-web">Add web as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/building">Build a web app</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/wasm">Compile to WebAssembly</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/initialization">Customize app initialization</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/embedding-flutter-web">Add Flutter to any web app</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/web-content-in-flutter">Web content in Flutter</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/renderers">Web renderers</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/web-images">Display images on the web</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/faq">Web FAQ</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-22-10" href="/platform-integration/windows" role="button" aria-expanded="false" aria-controls="header-sidenav-22-10">Windows</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-22-10"><li class="nav-item"><a class="nav-link" href="/platform-integration/windows/install-windows">Add Windows as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/windows/building">Build a Windows app</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-23" role="button" aria-expanded="false" aria-controls="header-sidenav-23">Packages & plugins</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-23"><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/using-packages">Use packages & plugins</a></li><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/developing-packages">Develop packages & plugins</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-23-3" href="/packages-and-plugins/swift-package-manager" role="button" aria-expanded="false" aria-controls="header-sidenav-23-3">Swift Package Manager</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-23-3"><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/swift-package-manager/for-app-developers">For app developers</a></li><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/swift-package-manager/for-plugin-authors">For plugin authors</a></li></ul></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/favorites">Flutter Favorites</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/flutter" target="_blank" rel="noopener">Package repository</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-24" role="button" aria-expanded="false" aria-controls="header-sidenav-24">Testing & debugging</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-24"><li class="nav-header">Testing</li><li class="nav-item"><a class="nav-link" href="/testing/overview">Overview</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-24-3" href="#header-sidenav-24-3" role="button" aria-expanded="false" aria-controls="header-sidenav-24-3">Unit testing</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-24-3"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/unit/introduction">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/unit/mocking">Mock dependencies</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-24-4" href="#header-sidenav-24-4" role="button" aria-expanded="false" aria-controls="header-sidenav-24-4">Widget testing</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-24-4"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/introduction">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/finders">Find widgets</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/scrolling">Simulate scrolling</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/tap-drag">Simulate user interaction</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-24-5" href="#header-sidenav-24-5" role="button" aria-expanded="false" aria-controls="header-sidenav-24-5">Integration testing</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-24-5"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/integration/introduction">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/testing/integration-tests">Write and run an integration test</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/integration/profiling">Profile an integration test</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/testing/testing-plugins">Test a plugin</a></li><li class="nav-item"><a class="nav-link" href="/testing/plugins-in-tests">Handle plugin code in tests</a></li><li class="nav-header">Debugging</li><li class="nav-item"><a class="nav-link" href="/testing/debugging">Debugging tools</a></li><li class="nav-item"><a class="nav-link" href="/testing/code-debugging">Debug your app programmatically</a></li><li class="nav-item"><a class="nav-link" href="/testing/native-debugging">Use a native language debugger</a></li><li class="nav-item"><a class="nav-link" href="/testing/build-modes">Flutter's build modes</a></li><li class="nav-item"><a class="nav-link" href="/testing/common-errors">Common Flutter errors</a></li><li class="nav-item"><a class="nav-link" href="/testing/errors">Handle errors</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/maintenance/error-reporting">Report errors to a service</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-25" role="button" aria-expanded="false" aria-controls="header-sidenav-25">Performance & optimization</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-25"><li class="nav-item"><a class="nav-link" href="/perf">Overview</a></li><li class="nav-item"><a class="nav-link" href="/perf/impeller">Impeller</a></li><li class="nav-item"><a class="nav-link" href="/perf/best-practices">Performance best practices</a></li><li class="nav-item"><a class="nav-link" href="/perf/app-size">App size</a></li><li class="nav-item"><a class="nav-link" href="/perf/deferred-components">Deferred components</a></li><li class="nav-item"><a class="nav-link" href="/perf/rendering-performance">Rendering performance</a></li><li class="nav-item"><a class="nav-link" href="/perf/ui-performance">Performance profiling</a></li><li class="nav-item"><a class="nav-link" href="/perf/web-performance">Performance profiling for web</a></li><li class="nav-item"><a class="nav-link" href="/perf/shader">Shader compilation jank</a></li><li class="nav-item"><a class="nav-link" href="/perf/metrics">Performance metrics</a></li><li class="nav-item"><a class="nav-link" href="/perf/isolates">Concurrency and isolates</a></li><li class="nav-item"><a class="nav-link" href="/perf/faq">Performance FAQ</a></li><li class="nav-item"><a class="nav-link" href="/perf/appendix">Appendix</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-26" role="button" aria-expanded="false" aria-controls="header-sidenav-26">Deployment</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-26"><li class="nav-item"><a class="nav-link" href="/deployment/obfuscate">Obfuscate Dart code</a></li><li class="nav-item"><a class="nav-link" href="/deployment/flavors">Create flavors of an app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/android">Build and release an Android app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/ios">Build and release an iOS app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/macos">Build and release a macOS app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/linux">Build and release a Linux app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/windows">Build and release a Windows app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/web">Build and release a web app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/cd">Set up continuous deployment</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-27" role="button" aria-expanded="false" aria-controls="header-sidenav-27">Add to an existing app</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-27"><li class="nav-item"><a class="nav-link" href="/add-to-app">Introduction</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-27-2" href="/add-to-app/android" role="button" aria-expanded="false" aria-controls="header-sidenav-27-2">Add to an Android app</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-27-2"><li class="nav-item"><a class="nav-link" href="/add-to-app/android/project-setup">Set up Android project</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-screen">Add a single Flutter screen</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-fragment">Add a Flutter Fragment</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-view">Add a Flutter View</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/plugin-setup">Use a Flutter plugin</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-27-3" href="/add-to-app/ios" role="button" aria-expanded="false" aria-controls="header-sidenav-27-3">Add to an iOS app</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-27-3"><li class="nav-item"><a class="nav-link" href="/add-to-app/ios/project-setup">Set up iOS project</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/ios/add-flutter-screen">Add a single Flutter screen</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/embedding-flutter-web">Add to a web app</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/debugging">Debug embedded Flutter module</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/multiple-flutters">Add multiple Flutter instances</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/performance">Loading sequence and performance</a></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-29" role="button" aria-expanded="false" aria-controls="header-sidenav-29">Tools & editors</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-29"><li class="nav-item"><a class="nav-link" href="/tools/android-studio">Android Studio & IntelliJ</a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code">Visual Studio Code</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-29-3" href="/tools/devtools" role="button" aria-expanded="false" aria-controls="header-sidenav-29-3">DevTools</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-29-3"><li class="nav-item"><a class="nav-link" href="/tools/devtools">Overview</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/android-studio">Run from Android Studio & IntelliJ</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/vscode">Run from VS Code</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/cli">Run from command line</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/inspector">Flutter inspector</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/performance">Performance view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/cpu-profiler">CPU Profiler view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/memory">Memory view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/console">Debug console view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/network">Network view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/debugger">Debugger</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/logging">Logging view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/app-size">App size tool</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/extensions">DevTools extensions</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/deep-links">Validate deep links</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/release-notes">Release notes</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/tools/sdk">SDK overview</a></li><li class="nav-item"><a class="nav-link" href="/tools/pubspec">Flutter's pubspec options</a></li><li class="nav-item"><a class="nav-link" href="/tools/flutter-fix">Automated fixes</a></li><li class="nav-item"><a class="nav-link" href="/tools/formatting">Code formatting</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-30" role="button" aria-expanded="false" aria-controls="header-sidenav-30">Flutter concepts</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-30"><li class="nav-item"><a class="nav-link" href="/resources/architectural-overview">Architectural overview</a></li><li class="nav-item"><a class="nav-link" href="/resources/inside-flutter">Inside Flutter</a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/constraints">Understanding constraints</a></li><li class="nav-item"><a class="nav-link" href="/testing/build-modes">Flutter's build modes</a></li><li class="nav-item"><a class="nav-link" href="/tools/hot-reload">Hot reload</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#header-sidenav-31" role="button" aria-expanded="false" aria-controls="header-sidenav-31">Resources</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-31"><li class="nav-item"><a class="nav-link" href="/resources/faq">FAQ</a></li><li class="nav-item"><a class="nav-link" href="/resources/books">Books</a></li><li class="nav-item"><a class="nav-link" href="/resources/videos">Videos</a></li><li class="nav-item"><a class="nav-link" href="/resources/courses">Courses</a></li><li class="nav-item"><a class="nav-link" href="/resources/bootstrap-into-dart">Learn Dart</a></li><li class="nav-item"><a class="nav-link" href="/resources/support">Get support</a></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-31-8" href="#header-sidenav-31-8" role="button" aria-expanded="false" aria-controls="header-sidenav-31-8">Contribute</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-31-8"><li class="nav-item"><a class="nav-link" href="/resources/bug-reports">Create useful bug reports</a></li><li class="nav-item"><a class="nav-link" href="https://github.com/flutter/flutter/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener">Contribute to Flutter</a></li><li class="nav-item"><a class="nav-link" href="/resources/design-docs">Discover proposed features</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#header-sidenav-31-9" href="/reference" role="button" aria-expanded="false" aria-controls="header-sidenav-31-9">Reference</a><ul class="nav flex-column flex-nowrap collapse" id="header-sidenav-31-9"><li class="nav-item"><a class="nav-link" href="/dash">Who is Dash?</a></li><li class="nav-item"><a class="nav-link" href="/reference/widgets">Widget index</a></li><li class="nav-item"><a class="nav-link" href="/reference/flutter-cli">flutter CLI</a></li><li class="nav-item"><a class="nav-link" href="https://api.flutter.dev" target="_blank" rel="noopener">API docs</a></li></ul></li></ul></li></ul></div><li class="nav-item dropdown"><a class="nav-link dropdown-toggle" id="platform-navbar-dropdown" href="https://flutter.dev/multi-platform" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Multi-Platform</a><div class="dropdown-menu" aria-labelledby="platform-navbar-dropdown"><a class="dropdown-item" href="https://flutter.dev/multi-platform/mobile">Mobile</a> <a class="dropdown-item" href="https://flutter.dev/multi-platform/web">Web</a> <a class="dropdown-item" href="https://flutter.dev/multi-platform/desktop">Desktop</a> <a class="dropdown-item" href="https://flutter.dev/multi-platform/embedded">Embedded</a></div></li><li class="nav-item dropdown"><a class="nav-link dropdown-toggle" id="dev-navbar-dropdown" href="https://flutter.dev/" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Development</a><div class="dropdown-menu" aria-labelledby="dev-navbar-dropdown"><a class="dropdown-item" href="https://flutter.dev/learn">Learn</a> <a class="dropdown-item" href="https://pub.dev/flutter/favorites" target="_blank">Flutter Favorites</a> <a class="dropdown-item" href="https://pub.dev/" target="_blank">Packages</a> <a class="dropdown-item" href="https://flutter.dev/monetization">Monetization</a> <a class="dropdown-item" href="https://flutter.dev/games">Games</a> <a class="dropdown-item" href="https://flutter.dev/news">News</a></div></li><li class="nav-item dropdown"><a class="nav-link dropdown-toggle" id="ecosystem-navbar-dropdown" href="https://flutter.dev/ecosystem" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Ecosystem</a><div class="dropdown-menu" aria-labelledby="ecosystem-navbar-dropdown"><a class="dropdown-item" href="https://flutter.dev/community">Community</a> <a class="dropdown-item" href="https://flutter.dev/events">Events</a> <a class="dropdown-item" href="https://flutter.dev/culture">Culture</a></div></li><li class="nav-item"><a class="nav-link" href="https://flutter.dev/showcase">Showcase</a></li><li class="nav-item dropdown docs-item"><a class="nav-link dropdown-toggle" id="docs-navbar-dropdown" href="/" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Docs</a><div class="dropdown-menu" aria-labelledby="docs-navbar-dropdown"><a class="dropdown-item" href="/release/whats-new">What's new</a> <a class="dropdown-item" href="/get-started/editor">Editor support</a> <a class="dropdown-item" href="/tools/hot-reload">Hot reload</a> <a class="dropdown-item" href="/perf/ui-performance">Profiling</a> <a class="dropdown-item" href="/get-started/install">Install Flutter</a> <a class="dropdown-item" href="/tools/devtools">DevTools</a> <a class="dropdown-item" href="/cookbook">Cookbook</a> <a class="dropdown-item" href="/codelabs">Codelabs</a></div></li></ul><form action="/search/" class="site-header__search form-inline"><input class="site-header__searchfield form-control search-field" type="search" name="q" id="q" autocomplete="off" placeholder="Search" aria-label="Search"></form></div></div><div class="site-header__social navbar-nav flex-row"><a class="nav-item nav-link nav-icon" href="https://twitter.com/FlutterDev" aria-label="Open Flutter's X (Twitter) in a new tab" target="_blank" rel="noreferrer"><svg><use href="/assets/images/social/x.svg#x"></use></svg> </a><a class="nav-item nav-link nav-icon" href="https://www.youtube.com/@flutterdev" aria-label="Open Flutter's YouTube in a new tab" target="_blank" rel="noreferrer"><svg><use href="/assets/images/social/youtube.svg#youtube"></use></svg> </a><a class="nav-item nav-link nav-icon" href="https://medium.com/flutter" aria-label="Open Flutter's Medium blog in a new tab" target="_blank" rel="noreferrer"><svg><use href="/assets/images/social/medium.svg#medium"></use></svg> </a><a class="nav-item nav-link nav-icon" href="https://github.com/flutter" aria-label="Open Flutter's GitHub in a new tab" target="_blank" rel="noreferrer"><svg><use href="/assets/images/social/github.svg#github"></use></svg></a></div><a class="site-header__cta btn btn-primary" href="/get-started/install/">Get started</a></nav></header><div class="site-banner site-banner--default" role="alert"><a href="https://medium.com/flutter/flutter-3-24-dart-3-5-204b7d20c45d">Flutter 3.24 and Dart 3.5</a> are here! Check out <a href="/release/whats-new">what's new</a> on the website.</div><div class="container-fluid position-relative"><div class="row flex-xl-nowrap"><div class="fixed-col site-sidebar site-sidebar--fixed col-12 col-md-3 col-xl-2 d-none d-md-block" data-fixed-column><ul class="nav flex-column"><li class="nav-header">Get started</li><li class="nav-item"><a class="nav-link" href="/get-started/install">Set up Flutter</a></li><li class="nav-item"><a class="nav-link active collapsible" data-toggle="collapse" href="#fixed-sidenav-3" role="button" aria-expanded="true" aria-controls="fixed-sidenav-3">Learn Flutter</a><ul class="nav flex-column flex-nowrap collapse show" id="fixed-sidenav-3"><li class="nav-item"><a class="nav-link" href="/get-started/learn-flutter">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/get-started/codelab">Write your first app</a></li><li class="nav-item"><a class="nav-link collapsible" data-toggle="collapse" data-target="#fixed-sidenav-3-3" href="#fixed-sidenav-3-3" role="button" aria-expanded="true" aria-controls="fixed-sidenav-3-3">Learn the fundamentals</a><ul class="nav flex-column flex-nowrap collapse show" id="fixed-sidenav-3-3"><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/dart">Intro to Dart</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/widgets">Widgets</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/layout">Layout</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/state-management">State management</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/user-input">Handling user input</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/networking">Networking and data</a></li><li class="nav-item"><a class="nav-link" href="/get-started/fundamentals/local-caching">Local data and caching</a></li></ul></li><li class="nav-item"><a class="nav-link active collapsible" data-toggle="collapse" data-target="#fixed-sidenav-3-4" href="/get-started/flutter-for" role="button" aria-expanded="true" aria-controls="fixed-sidenav-3-4">From another platform?</a><ul class="nav flex-column flex-nowrap collapse show" id="fixed-sidenav-3-4"><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/android-devs">Flutter for Android devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/swiftui-devs">Flutter for SwiftUI devs</a></li><li class="nav-item"><a class="nav-link active" href="/get-started/flutter-for/uikit-devs">Flutter for UIKit devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/react-native-devs">Flutter for React Native devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/web-devs">Flutter for web devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/xamarin-forms-devs">Flutter for Xamarin.Forms devs</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/declarative">Introduction to declarative UI</a></li><li class="nav-item"><a class="nav-link" href="/get-started/flutter-for/dart-swift-concurrency">Flutter versus Swift concurrency</a></li></ul></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/codelabs">Codelabs</a></li><li class="nav-item"><a class="nav-link" href="/cookbook">Cookbook</a></li><li class="nav-item"><a class="nav-link" href="https://flutter.github.io/samples/" target="_blank" rel="noopener">Demos and samples</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-4" role="button" aria-expanded="false" aria-controls="fixed-sidenav-4">Stay up to date</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-4"><li class="nav-item"><a class="nav-link" href="/release/upgrade">Upgrade</a></li><li class="nav-item"><a class="nav-link" href="/release/archive">SDK archive</a></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/release/whats-new">What's new</a></li><li class="nav-item"><a class="nav-link" href="/release/release-notes">Release notes</a></li><li class="nav-item"><a class="nav-link" href="/release/breaking-changes">Breaking changes</a></li><li class="nav-item"><a class="nav-link" href="/release/compatibility-policy">Compatibility policy</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-5" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5">App solutions</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5"><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-1" href="#fixed-sidenav-5-1" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-1">AI</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-1"><li class="nav-item"><a class="nav-link" href="/resources/ai-overview">Overview</a></li><li class="nav-item"><a class="nav-link" href="https://ai.google.dev/gemini-api/docs/get-started/dart" target="_blank" rel="noopener">Get started with the Gemini API</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/google_generative_ai" target="_blank" rel="noopener">Google AI Dart SDK (pub.dev)</a></li><li class="nav-item"><a class="nav-link" href="https://www.youtube.com/watch?v=1AuzJEiHjO4" target="_blank" rel="noopener">Build with Google AI Dart SDK (video)</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-2" href="#fixed-sidenav-5-2" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-2">Firebase & Firestore</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-2"><li class="nav-item"><a class="nav-link" href="/data-and-backend/firebase">Overview</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/flutter" target="_blank" rel="noopener">Discover Firebase for Flutter</a></li><li class="nav-item"><a class="nav-link" href="https://www.youtube.com/watch?v=wUSkeTaBonA" target="_blank" rel="noopener">Get to know Firebase for Flutter</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps" target="_blank" rel="noopener">Add a user authentication flow to a Flutter app using FirebaseUI</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-get-to-know-web" target="_blank" rel="noopener">Get to know Firebase for web</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-3" href="#fixed-sidenav-5-3" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-3">Games</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-3"><li class="nav-item"><a class="nav-link" href="/resources/games-toolkit">Overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/games/achievements-leaderboard">Add achievements and leaderboards</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/build-leaderboards-with-firestore#0" target="_blank" rel="noopener">Build leaderboards with Firestore</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/google-mobile-ads">Add advertising</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/games/firestore-multiplayer">Add multiplayer support</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" target="_blank" rel="noopener">Add in-app purchases</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps" target="_blank" rel="noopener">Add user authentication</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/crashlytics/get-started?platform=flutter" target="_blank" rel="noopener">Debug using Crashlytics</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-flame-brick-breaker" target="_blank" rel="noopener">Intro to Flame with Flutter</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-4" href="#fixed-sidenav-5-4" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-4">Monetization</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-4"><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-4-1" href="#fixed-sidenav-5-4-1" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-4-1">Advertising</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-4-1"><li class="nav-item"><a class="nav-link" href="/resources/ads-overview">Ads overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/google-mobile-ads">Add advertising</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/admob-ads-in-flutter" target="_blank" rel="noopener">Add AdMob ads to your Flutter app</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/admob-inline-ads-in-flutter" target="_blank" rel="noopener">Add an AdMob banner and native inline ads</a></li><li class="nav-item"><a class="nav-link" href="https://developers.google.com/admob/flutter/mediation" target="_blank" rel="noopener">Google AdMob mediation</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/interactive_media_ads" target="_blank" rel="noopener">Interactive Media Ads SDK</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-4-2" href="#fixed-sidenav-5-4-2" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-4-2">In-app purchases</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-4-2"><li class="nav-item"><a class="nav-link" href="/resources/in-app-purchases-overview">In-app purchases overview</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases" target="_blank" rel="noopener">Add in-app purchases</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-4-3" href="#fixed-sidenav-5-4-3" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-4-3">Payments</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-4-3"><li class="nav-item"><a class="nav-link" href="/resources/payments-overview">Payments overview</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/pay" target="_blank" rel="noopener">Google pay package</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-5" href="#fixed-sidenav-5-5" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-5">Maps</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-5"><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/google-maps-in-flutter" target="_blank" rel="noopener">Add Google maps to a Flutter app</a></li><li class="nav-item"><a class="nav-link" href="https://developers.google.com/maps/flutter-package" target="_blank" rel="noopener">Google Maps package</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-5-6" href="#fixed-sidenav-5-6" role="button" aria-expanded="false" aria-controls="fixed-sidenav-5-6">News</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/resources/news-toolkit">Build a news app</a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-header">User interface</li><li class="nav-item"><a class="nav-link" href="/ui">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/ui/widgets">Widget catalog</a></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-10" role="button" aria-expanded="false" aria-controls="fixed-sidenav-10">Layout</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-10"><li class="nav-item"><a class="nav-link" href="/ui/layout">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/tutorial">Build a layout</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-10-3" href="/ui/layout/lists" role="button" aria-expanded="false" aria-controls="fixed-sidenav-10-3">Lists & grids</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-10-3"><li class="nav-item"><a class="nav-link" href="/cookbook/lists/basic-list">Create and use lists</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/horizontal-list">Create a horizontal list</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/grid-lists">Create a grid view</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/mixed-list">Create lists with different types of items</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/spaced-items">Create lists with spaced items</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/long-lists">Work with long lists</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-10-4" href="/ui/layout/scrolling" role="button" aria-expanded="false" aria-controls="fixed-sidenav-10-4">Scrolling</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-10-4"><li class="nav-item"><a class="nav-link" href="/ui/layout/scrolling">Overview</a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/scrolling/slivers">Use slivers to achieve fancy scrolling</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/lists/floating-app-bar">Place a floating app bar above a list</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/parallax-scrolling">Create a scrolling parallax effect</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-11" role="button" aria-expanded="false" aria-controls="fixed-sidenav-11">Adaptive & responsive design</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-11"><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive">Overview</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/general">General approach</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/safearea-mediaquery">SafeArea & MediaQuery</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/large-screens">Large screens & foldables</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/input">User input & accessibility</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/capabilities">Capabilities & policies</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/best-practices">Best practices</a></li><li class="nav-item"><a class="nav-link" href="/ui/adaptive-responsive/more-info">Additional resources</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-12" role="button" aria-expanded="false" aria-controls="fixed-sidenav-12">Design & theming</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-12"><li class="nav-item"><a class="nav-link" href="/cookbook/design/themes">Share styles with themes</a></li><li class="nav-item"><a class="nav-link" href="/ui/design/material">Material design</a></li><li class="nav-item"><a class="nav-link" href="/release/breaking-changes/material-3-migration">Migrate to Material 3</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-12-4" href="/ui/design/text" role="button" aria-expanded="false" aria-controls="fixed-sidenav-12-4">Text</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-12-4"><li class="nav-item"><a class="nav-link" href="/ui/design/text/typography">Fonts & typography</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/fonts">Use a custom font</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/package-fonts">Export fonts from a package</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/packages/google_fonts" target="_blank" rel="noopener">Google Fonts package</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-12-5" href="/ui/design/graphics" role="button" aria-expanded="false" aria-controls="fixed-sidenav-12-5">Custom graphics</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-12-5"><li class="nav-item"><a class="nav-link" href="/ui/design/graphics/fragment-shaders">Use custom fragment shaders</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-13" role="button" aria-expanded="false" aria-controls="fixed-sidenav-13">Interactivity</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-13"><li class="nav-item"><a class="nav-link" href="/ui/interactivity">Add interactivity to your app</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-13-2" href="/ui/interactivity/gestures" role="button" aria-expanded="false" aria-controls="fixed-sidenav-13-2">Gestures</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-13-2"><li class="nav-item"><a class="nav-link" href="/ui/interactivity/gestures">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/handling-taps">Handle taps</a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/gestures/drag-outside">Drag an object outside an app</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/drag-a-widget">Drag a UI element within an app</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/ripples">Add Material touch ripples</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/gestures/dismissible">Implement swipe to dismiss</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-13-3" href="/ui/interactivity/input" role="button" aria-expanded="false" aria-controls="fixed-sidenav-13-3">Input & forms</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-13-3"><li class="nav-item"><a class="nav-link" href="/cookbook/forms/text-input">Create and style a text field</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/retrieve-input">Retrieve the value of a text field</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/text-field-changes">Handle changes to a text field</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/focus">Manage focus in text fields</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/forms/validation">Build a form with validation</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/snackbars">Display a snackbar</a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/actions-and-shortcuts">Implement actions & shortcuts</a></li><li class="nav-item"><a class="nav-link" href="/ui/interactivity/focus">Manage keyboard focus</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-14" role="button" aria-expanded="false" aria-controls="fixed-sidenav-14">Assets & media</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-14"><li class="nav-item"><a class="nav-link" href="/ui/assets/assets-and-images">Add assets and images</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/images/network-image">Display images from the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/images/fading-in-images">Fade in images with a placeholder</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/plugins/play-video">Play and pause a video</a></li><li class="nav-item"><a class="nav-link" href="/ui/assets/asset-transformation">Transform assets at build time</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-15" role="button" aria-expanded="false" aria-controls="fixed-sidenav-15">Navigation & routing</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-15"><li class="nav-item"><a class="nav-link" href="/ui/navigation">Overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/tabs">Add tabs to your app</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/navigation-basics">Navigate to a new screen and back</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/passing-data">Send data to a new screen</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/returning-data">Return data from a screen</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/design/drawer">Add a drawer to a screen</a></li><li class="nav-item"><a class="nav-link" href="/ui/navigation/deep-linking">Set up deep linking</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/set-up-app-links">Set up app links for Android</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/navigation/set-up-universal-links">Set up universal links for iOS</a></li><li class="nav-item"><a class="nav-link" href="/ui/navigation/url-strategies">Configure web URL strategies</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-16" role="button" aria-expanded="false" aria-controls="fixed-sidenav-16">Animations & transitions</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-16"><li class="nav-item"><a class="nav-link" href="/ui/animations">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/tutorial">Tutorial</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/implicit-animations">Implicit animations</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/animated-container">Animate the properties of a container</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/opacity-animation">Fade a widget in and out</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/hero-animations">Hero animations</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/page-route-animation">Animate a page route transition</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/animation/physics-simulation">Animate using a physics simulation</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/staggered-animations">Staggered animations</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/effects/staggered-menu-animation">Create a staggered menu animation</a></li><li class="nav-item"><a class="nav-link" href="/ui/animations/overview">API overview</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-17" role="button" aria-expanded="false" aria-controls="fixed-sidenav-17">Accessibility & internationalization</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-17"><li class="nav-item"><a class="nav-link" href="/ui/accessibility-and-internationalization/accessibility">Accessibility</a></li><li class="nav-item"><a class="nav-link" href="/ui/accessibility-and-internationalization/internationalization">Internationalization</a></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-header">Beyond UI</li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-20" role="button" aria-expanded="false" aria-controls="fixed-sidenav-20">Data & backend</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-20"><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-20-1" href="/data-and-backend/state-mgmt" role="button" aria-expanded="false" aria-controls="fixed-sidenav-20-1">State management</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-20-1"><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/intro">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/declarative">Think declaratively</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/ephemeral-vs-app">Ephemeral vs app state</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/simple">Simple app state management</a></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/state-mgmt/options">Options</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-20-2" href="/data-and-backend/networking" role="button" aria-expanded="false" aria-controls="fixed-sidenav-20-2">Networking & http</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-20-2"><li class="nav-item"><a class="nav-link" href="/data-and-backend/networking">Overview</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/fetch-data">Fetch data from the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/authenticated-requests">Make authenticated requests</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/send-data">Send data to the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/update-data">Update data over the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/delete-data">Delete data on the internet</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/web-sockets">Communicate with WebSockets</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-20-3" href="/data-and-backend/serialization" role="button" aria-expanded="false" aria-controls="fixed-sidenav-20-3">Serialization</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-20-3"><li class="nav-item"><a class="nav-link" href="/data-and-backend/serialization/json">JSON serialization</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/networking/background-parsing">Parse JSON in the background</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-20-4" href="/data-and-backend/persistence" role="button" aria-expanded="false" aria-controls="fixed-sidenav-20-4">Persistence</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-20-4"><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/key-value">Store key-value data on disk</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/reading-writing-files">Read and write files</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/persistence/sqlite">Persist data with SQLite</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-20-5" href="/data-and-backend/firebase" role="button" aria-expanded="false" aria-controls="fixed-sidenav-20-5">Firebase</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-20-5"><li class="nav-item"><a class="nav-link" href="/data-and-backend/firebase">Overview</a></li><li class="nav-item"><a class="nav-link" href="https://firebase.google.com/docs/flutter/setup" target="_blank" rel="noopener">Add Firebase to your Flutter app</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/data-and-backend/google-apis">Google APIs</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-21" role="button" aria-expanded="false" aria-controls="fixed-sidenav-21">App architecture</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-21"><li class="nav-item"><a class="nav-link" href="/app-architecture">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/concepts">Architecture concepts</a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/guide">Guide to app architecture</a></li><li class="nav-item"><a class="nav-link" href="/app-architecture/recommendations">Recommendations</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-21-5" href="/cookbook/architecture" role="button" aria-expanded="false" aria-controls="fixed-sidenav-21-5">Design patterns</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-21-5"><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/optimistic-state">Optimistic state</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/key-value-data">Persistent storage architecture: Key-value data</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/sql">Persistent storage architecture: SQL</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/architecture/offline-first">Offline-first</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-22" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22">Platform integration</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22"><li class="nav-item"><a class="nav-link" href="/reference/supported-platforms">Supported platforms</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/desktop">Build desktop apps with Flutter</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/platform-channels">Write platform-specific code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/platform-adaptations">Automatic platform adaptations</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-22-5" href="/platform-integration/android" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22-5">Android</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22-5"><li class="nav-item"><a class="nav-link" href="/platform-integration/android/install-android">Add Android as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/splash-screen">Add a splash screen</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/predictive-back">Add predictive back</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/c-interop">Bind to native code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/platform-views">Host a native Android view</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/compose-activity">Launch a Jetpack Compose activity</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/restore-state-android">Restore state on Android</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/android/chromeos">Target ChromeOS with Android</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-22-6" href="/platform-integration/ios" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22-6">iOS</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22-6"><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/install-ios">Add iOS as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-latest">Flutter on latest iOS</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/apple-frameworks">Leverage Apple's system libraries</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/launch-screen">Add a launch screen</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-app-clip">Add iOS App Clip support</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/app-extensions">Add iOS app extensions</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/c-interop">Bind to native code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/platform-views">Host a native iOS view</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/ios-debugging">Enable debugging on iOS</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/ios/restore-state-ios">Restore state on iOS</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-22-7" href="/platform-integration/linux" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22-7">Linux</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22-7"><li class="nav-item"><a class="nav-link" href="/platform-integration/linux/install-linux">Add Linux as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/linux/building">Build a Linux app</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-22-8" href="/platform-integration/macos" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22-8">macOS</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22-8"><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/install-macos">Add macOS as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/building">Build a macOS app</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/c-interop">Bind to native code</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/macos/platform-views">Host a native macOS view</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-22-9" href="/platform-integration/web" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22-9">Web</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22-9"><li class="nav-item"><a class="nav-link" href="/platform-integration/web/">Web support in Flutter</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/install-web">Add web as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/building">Build a web app</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/wasm">Compile to WebAssembly</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/initialization">Customize app initialization</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/embedding-flutter-web">Add Flutter to any web app</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/web-content-in-flutter">Web content in Flutter</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/renderers">Web renderers</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/web-images">Display images on the web</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/faq">Web FAQ</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-22-10" href="/platform-integration/windows" role="button" aria-expanded="false" aria-controls="fixed-sidenav-22-10">Windows</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-22-10"><li class="nav-item"><a class="nav-link" href="/platform-integration/windows/install-windows">Add Windows as build target</a></li><li class="nav-item"><a class="nav-link" href="/platform-integration/windows/building">Build a Windows app</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-23" role="button" aria-expanded="false" aria-controls="fixed-sidenav-23">Packages & plugins</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-23"><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/using-packages">Use packages & plugins</a></li><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/developing-packages">Develop packages & plugins</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-23-3" href="/packages-and-plugins/swift-package-manager" role="button" aria-expanded="false" aria-controls="fixed-sidenav-23-3">Swift Package Manager</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-23-3"><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/swift-package-manager/for-app-developers">For app developers</a></li><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/swift-package-manager/for-plugin-authors">For plugin authors</a></li></ul></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/packages-and-plugins/favorites">Flutter Favorites</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev/flutter" target="_blank" rel="noopener">Package repository</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-24" role="button" aria-expanded="false" aria-controls="fixed-sidenav-24">Testing & debugging</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-24"><li class="nav-header">Testing</li><li class="nav-item"><a class="nav-link" href="/testing/overview">Overview</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-24-3" href="#fixed-sidenav-24-3" role="button" aria-expanded="false" aria-controls="fixed-sidenav-24-3">Unit testing</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-24-3"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/unit/introduction">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/unit/mocking">Mock dependencies</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-24-4" href="#fixed-sidenav-24-4" role="button" aria-expanded="false" aria-controls="fixed-sidenav-24-4">Widget testing</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-24-4"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/introduction">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/finders">Find widgets</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/scrolling">Simulate scrolling</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/widget/tap-drag">Simulate user interaction</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-24-5" href="#fixed-sidenav-24-5" role="button" aria-expanded="false" aria-controls="fixed-sidenav-24-5">Integration testing</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-24-5"><li class="nav-item"><a class="nav-link" href="/cookbook/testing/integration/introduction">Introduction</a></li><li class="nav-item"><a class="nav-link" href="/testing/integration-tests">Write and run an integration test</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/testing/integration/profiling">Profile an integration test</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/testing/testing-plugins">Test a plugin</a></li><li class="nav-item"><a class="nav-link" href="/testing/plugins-in-tests">Handle plugin code in tests</a></li><li class="nav-header">Debugging</li><li class="nav-item"><a class="nav-link" href="/testing/debugging">Debugging tools</a></li><li class="nav-item"><a class="nav-link" href="/testing/code-debugging">Debug your app programmatically</a></li><li class="nav-item"><a class="nav-link" href="/testing/native-debugging">Use a native language debugger</a></li><li class="nav-item"><a class="nav-link" href="/testing/build-modes">Flutter's build modes</a></li><li class="nav-item"><a class="nav-link" href="/testing/common-errors">Common Flutter errors</a></li><li class="nav-item"><a class="nav-link" href="/testing/errors">Handle errors</a></li><li class="nav-item"><a class="nav-link" href="/cookbook/maintenance/error-reporting">Report errors to a service</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-25" role="button" aria-expanded="false" aria-controls="fixed-sidenav-25">Performance & optimization</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-25"><li class="nav-item"><a class="nav-link" href="/perf">Overview</a></li><li class="nav-item"><a class="nav-link" href="/perf/impeller">Impeller</a></li><li class="nav-item"><a class="nav-link" href="/perf/best-practices">Performance best practices</a></li><li class="nav-item"><a class="nav-link" href="/perf/app-size">App size</a></li><li class="nav-item"><a class="nav-link" href="/perf/deferred-components">Deferred components</a></li><li class="nav-item"><a class="nav-link" href="/perf/rendering-performance">Rendering performance</a></li><li class="nav-item"><a class="nav-link" href="/perf/ui-performance">Performance profiling</a></li><li class="nav-item"><a class="nav-link" href="/perf/web-performance">Performance profiling for web</a></li><li class="nav-item"><a class="nav-link" href="/perf/shader">Shader compilation jank</a></li><li class="nav-item"><a class="nav-link" href="/perf/metrics">Performance metrics</a></li><li class="nav-item"><a class="nav-link" href="/perf/isolates">Concurrency and isolates</a></li><li class="nav-item"><a class="nav-link" href="/perf/faq">Performance FAQ</a></li><li class="nav-item"><a class="nav-link" href="/perf/appendix">Appendix</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-26" role="button" aria-expanded="false" aria-controls="fixed-sidenav-26">Deployment</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-26"><li class="nav-item"><a class="nav-link" href="/deployment/obfuscate">Obfuscate Dart code</a></li><li class="nav-item"><a class="nav-link" href="/deployment/flavors">Create flavors of an app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/android">Build and release an Android app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/ios">Build and release an iOS app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/macos">Build and release a macOS app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/linux">Build and release a Linux app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/windows">Build and release a Windows app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/web">Build and release a web app</a></li><li class="nav-item"><a class="nav-link" href="/deployment/cd">Set up continuous deployment</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-27" role="button" aria-expanded="false" aria-controls="fixed-sidenav-27">Add to an existing app</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-27"><li class="nav-item"><a class="nav-link" href="/add-to-app">Introduction</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-27-2" href="/add-to-app/android" role="button" aria-expanded="false" aria-controls="fixed-sidenav-27-2">Add to an Android app</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-27-2"><li class="nav-item"><a class="nav-link" href="/add-to-app/android/project-setup">Set up Android project</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-screen">Add a single Flutter screen</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-fragment">Add a Flutter Fragment</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/add-flutter-view">Add a Flutter View</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/android/plugin-setup">Use a Flutter plugin</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-27-3" href="/add-to-app/ios" role="button" aria-expanded="false" aria-controls="fixed-sidenav-27-3">Add to an iOS app</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-27-3"><li class="nav-item"><a class="nav-link" href="/add-to-app/ios/project-setup">Set up iOS project</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/ios/add-flutter-screen">Add a single Flutter screen</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/platform-integration/web/embedding-flutter-web">Add to a web app</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/debugging">Debug embedded Flutter module</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/multiple-flutters">Add multiple Flutter instances</a></li><li class="nav-item"><a class="nav-link" href="/add-to-app/performance">Loading sequence and performance</a></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-29" role="button" aria-expanded="false" aria-controls="fixed-sidenav-29">Tools & editors</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-29"><li class="nav-item"><a class="nav-link" href="/tools/android-studio">Android Studio & IntelliJ</a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code">Visual Studio Code</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-29-3" href="/tools/devtools" role="button" aria-expanded="false" aria-controls="fixed-sidenav-29-3">DevTools</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-29-3"><li class="nav-item"><a class="nav-link" href="/tools/devtools">Overview</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/android-studio">Run from Android Studio & IntelliJ</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/vscode">Run from VS Code</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/cli">Run from command line</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/inspector">Flutter inspector</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/performance">Performance view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/cpu-profiler">CPU Profiler view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/memory">Memory view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/console">Debug console view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/network">Network view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/debugger">Debugger</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/logging">Logging view</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/app-size">App size tool</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/extensions">DevTools extensions</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/deep-links">Validate deep links</a></li><li class="nav-item"><a class="nav-link" href="/tools/devtools/release-notes">Release notes</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/tools/sdk">SDK overview</a></li><li class="nav-item"><a class="nav-link" href="/tools/pubspec">Flutter's pubspec options</a></li><li class="nav-item"><a class="nav-link" href="/tools/flutter-fix">Automated fixes</a></li><li class="nav-item"><a class="nav-link" href="/tools/formatting">Code formatting</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-30" role="button" aria-expanded="false" aria-controls="fixed-sidenav-30">Flutter concepts</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-30"><li class="nav-item"><a class="nav-link" href="/resources/architectural-overview">Architectural overview</a></li><li class="nav-item"><a class="nav-link" href="/resources/inside-flutter">Inside Flutter</a></li><li class="nav-item"><a class="nav-link" href="/ui/layout/constraints">Understanding constraints</a></li><li class="nav-item"><a class="nav-link" href="/testing/build-modes">Flutter's build modes</a></li><li class="nav-item"><a class="nav-link" href="/tools/hot-reload">Hot reload</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#fixed-sidenav-31" role="button" aria-expanded="false" aria-controls="fixed-sidenav-31">Resources</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-31"><li class="nav-item"><a class="nav-link" href="/resources/faq">FAQ</a></li><li class="nav-item"><a class="nav-link" href="/resources/books">Books</a></li><li class="nav-item"><a class="nav-link" href="/resources/videos">Videos</a></li><li class="nav-item"><a class="nav-link" href="/resources/courses">Courses</a></li><li class="nav-item"><a class="nav-link" href="/resources/bootstrap-into-dart">Learn Dart</a></li><li class="nav-item"><a class="nav-link" href="/resources/support">Get support</a></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-31-8" href="#fixed-sidenav-31-8" role="button" aria-expanded="false" aria-controls="fixed-sidenav-31-8">Contribute</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-31-8"><li class="nav-item"><a class="nav-link" href="/resources/bug-reports">Create useful bug reports</a></li><li class="nav-item"><a class="nav-link" href="https://github.com/flutter/flutter/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener">Contribute to Flutter</a></li><li class="nav-item"><a class="nav-link" href="/resources/design-docs">Discover proposed features</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#fixed-sidenav-31-9" href="/reference" role="button" aria-expanded="false" aria-controls="fixed-sidenav-31-9">Reference</a><ul class="nav flex-column flex-nowrap collapse" id="fixed-sidenav-31-9"><li class="nav-item"><a class="nav-link" href="/dash">Who is Dash?</a></li><li class="nav-item"><a class="nav-link" href="/reference/widgets">Widget index</a></li><li class="nav-item"><a class="nav-link" href="/reference/flutter-cli">flutter CLI</a></li><li class="nav-item"><a class="nav-link" href="https://api.flutter.dev" target="_blank" rel="noopener">API docs</a></li></ul></li></ul></li></ul></div><main class="site-content col-12 col-md-9 offset-md-3 col-xl-8 offset-xl-2 col-xxl-8 offset-xxl-2"><div id="site-toc--side" class="site-toc fixed-col col-xl-2 order-3" data-fixed-column><header class="site-toc__title">Contents</header><ul class="section-nav"><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#overview">Overview</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#views-vs-widgets">Views vs. Widgets</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#updating-widgets">Updating widgets</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#widget-layout">Widget layout</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#removing-widgets">Removing Widgets</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#animations">Animations</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#drawing-on-the-screen">Drawing on the screen</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#widget-opacity">Widget opacity</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#custom-widgets">Custom Widgets</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#managing-dependencies">Managing dependencies</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#navigation">Navigation</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#navigating-between-pages">Navigating between pages</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#navigating-to-another-app">Navigating to another app</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#manually-pop-back">Manually pop back</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#handling-localization">Handling localization</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#viewcontrollers">ViewControllers</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#equivalent-of-viewcontroller-in-flutter">Equivalent of ViewController in Flutter</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#listening-to-lifecycle-events">Listening to lifecycle events</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#layouts">Layouts</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#displaying-a-list-view">Displaying a list view</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#detecting-what-was-clicked">Detecting what was clicked</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#dynamically-updating-listview">Dynamically updating ListView</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#creating-a-scroll-view">Creating a scroll view</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#gesture-detection-and-touch-event-handling">Gesture detection and touch event handling</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#adding-a-click-listener">Adding a click listener</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#handling-other-gestures">Handling other gestures</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#themes-styles-and-media">Themes, styles, and media</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#using-a-theme">Using a theme</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#using-custom-fonts">Using custom fonts</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#styling-text">Styling text</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#bundling-images-in-apps">Bundling images in apps</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#form-input">Form input</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#retrieving-user-input">Retrieving user input</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#placeholder-in-a-text-field">Placeholder in a text field</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#showing-validation-errors">Showing validation errors</a></li></ul></li><li class="toc-entry nav-item toc-h2"><a class="nav-link" href="#threading-asynchronicity">Threading & asynchronicity</a><ul class="nav"><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#writing-asynchronous-code">Writing asynchronous code</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#moving-to-the-background-thread">Moving to the background thread</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#making-network-requests">Making network requests</a></li><li class="toc-entry nav-item toc-h3"><a class="nav-link" href="#showing-the-progress-on-long-running-tasks">Showing the progress on long-running tasks</a></li></ul></li></ul></div><div class="container"><header class="site-content__title" id="site-content-title"><h1>Flutter for UIKit developers</h1><nav class="breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb-list" vocab="https://schema.org/" typeof="BreadcrumbList"><li class="breadcrumb-item" property="itemListElement" typeof="ListItem"><a href="/get-started" property="item" typeof="WebPage"><span property="name">Get started</span></a><meta property="position" content="0"><span class="material-symbols-outlined child-icon" aria-hidden="true">chevron_right</span></li><li class="breadcrumb-item" property="itemListElement" typeof="ListItem"><a href="/get-started/flutter-for" property="item" typeof="WebPage"><span property="name">Flutter for</span></a><meta property="position" content="1"><span class="material-symbols-outlined child-icon" aria-hidden="true">chevron_right</span></li><li class="breadcrumb-item active" property="itemListElement" typeof="ListItem" aria-current="page"><a href="/get-started/flutter-for/uikit-devs" property="item" typeof="WebPage"><span property="name">Flutter for UIKit developers</span></a><meta property="position" content="2"></li></ol></nav></header><div id="site-toc--inline" class="site-toc toc-collapsible toc-collapsed"><header class="site-toc__title">Contents <span class="site-toc--inline__toggle toc-toggle-down" title="Expand table of contents"><i class="material-symbols" aria-hidden="true">keyboard_arrow_down</i></span> <span class="site-toc--inline__toggle toc-toggle-up" title="Collapse table of contents"><i class="material-symbols" aria-hidden="true">keyboard_arrow_up</i></span></header><ul class="section-nav"><li class="toc-entry toc-h2"><a href="#overview">Overview</a><ul><li class="toc-entry toc-h3"><a href="#views-vs-widgets">Views vs. Widgets</a></li><li class="toc-entry toc-h3"><a href="#updating-widgets">Updating widgets</a></li><li class="toc-entry toc-h3"><a href="#widget-layout">Widget layout</a></li><li class="toc-entry toc-h3"><a href="#removing-widgets">Removing Widgets</a></li><li class="toc-entry toc-h3"><a href="#animations">Animations</a></li><li class="toc-entry toc-h3"><a href="#drawing-on-the-screen">Drawing on the screen</a></li><li class="toc-entry toc-h3"><a href="#widget-opacity">Widget opacity</a></li><li class="toc-entry toc-h3"><a href="#custom-widgets">Custom Widgets</a></li><li class="toc-entry toc-h3"><a href="#managing-dependencies">Managing dependencies</a></li></ul></li><li class="toc-entry toc-h2"><a href="#navigation">Navigation</a><ul><li class="toc-entry toc-h3"><a href="#navigating-between-pages">Navigating between pages</a></li><li class="toc-entry toc-h3"><a href="#navigating-to-another-app">Navigating to another app</a></li><li class="toc-entry toc-h3"><a href="#manually-pop-back">Manually pop back</a></li><li class="toc-entry toc-h3"><a href="#handling-localization">Handling localization</a></li></ul></li><li class="toc-entry toc-h2"><a href="#viewcontrollers">ViewControllers</a><ul><li class="toc-entry toc-h3"><a href="#equivalent-of-viewcontroller-in-flutter">Equivalent of ViewController in Flutter</a></li><li class="toc-entry toc-h3"><a href="#listening-to-lifecycle-events">Listening to lifecycle events</a></li></ul></li><li class="toc-entry toc-h2"><a href="#layouts">Layouts</a><ul><li class="toc-entry toc-h3"><a href="#displaying-a-list-view">Displaying a list view</a></li><li class="toc-entry toc-h3"><a href="#detecting-what-was-clicked">Detecting what was clicked</a></li><li class="toc-entry toc-h3"><a href="#dynamically-updating-listview">Dynamically updating ListView</a></li><li class="toc-entry toc-h3"><a href="#creating-a-scroll-view">Creating a scroll view</a></li></ul></li><li class="toc-entry toc-h2"><a href="#gesture-detection-and-touch-event-handling">Gesture detection and touch event handling</a><ul><li class="toc-entry toc-h3"><a href="#adding-a-click-listener">Adding a click listener</a></li><li class="toc-entry toc-h3"><a href="#handling-other-gestures">Handling other gestures</a></li></ul></li><li class="toc-entry toc-h2"><a href="#themes-styles-and-media">Themes, styles, and media</a><ul><li class="toc-entry toc-h3"><a href="#using-a-theme">Using a theme</a></li><li class="toc-entry toc-h3"><a href="#using-custom-fonts">Using custom fonts</a></li><li class="toc-entry toc-h3"><a href="#styling-text">Styling text</a></li><li class="toc-entry toc-h3"><a href="#bundling-images-in-apps">Bundling images in apps</a></li></ul></li><li class="toc-entry toc-h2"><a href="#form-input">Form input</a><ul><li class="toc-entry toc-h3"><a href="#retrieving-user-input">Retrieving user input</a></li><li class="toc-entry toc-h3"><a href="#placeholder-in-a-text-field">Placeholder in a text field</a></li><li class="toc-entry toc-h3"><a href="#showing-validation-errors">Showing validation errors</a></li></ul></li><li class="toc-entry toc-h2"><a href="#threading-asynchronicity">Threading & asynchronicity</a><ul><li class="toc-entry toc-h3"><a href="#writing-asynchronous-code">Writing asynchronous code</a></li><li class="toc-entry toc-h3"><a href="#moving-to-the-background-thread">Moving to the background thread</a></li><li class="toc-entry toc-h3"><a href="#making-network-requests">Making network requests</a></li><li class="toc-entry toc-h3"><a href="#showing-the-progress-on-long-running-tasks">Showing the progress on long-running tasks</a></li></ul></li></ul><span class="site-toc--inline__toggle toc-toggle-more-items" title="Expand table of contents"><i class="material-symbols" aria-hidden="true">more_horiz</i></span></div> <?code-excerpt path-base="get-started/flutter-for/ios_devs"?> <p>iOS developers with experience using UIKit who want to write mobile apps using Flutter should review this guide. It explains how to apply existing UIKit knowledge to Flutter.</p><aside class="alert alert-info"><div class="alert-header"><i class="material-symbols" aria-hidden="true">info</i> <span>Note</span></div><div class="alert-content"><p>If you have experience building apps with SwiftUI, check out <a href="/get-started/flutter-for/swiftui-devs">Flutter for SwiftUI developers</a> instead.</p></div></aside><p>Flutter is a framework for building cross-platform applications that uses the Dart programming language. To understand some differences between programming with Dart and programming with Swift, check out <a href="https://dart.dev/guides/language/coming-from/swift-to-dart">Learning Dart as a Swift Developer</a> and <a href="/get-started/flutter-for/dart-swift-concurrency">Flutter concurrency for Swift developers</a>.</p><p>Your iOS and UIKit knowledge and experience are highly valuable when building with Flutter. Flutter also makes a number of adaptations to app behavior when running on iOS. To learn how, see <a href="/platform-integration/platform-adaptations">Platform adaptations</a>.</p><aside class="alert alert-success"><div class="alert-header"><i class="material-symbols" aria-hidden="true">lightbulb</i> <span>Tip</span></div><div class="alert-content"><p>To integrate Flutter code into an <strong>existing</strong> iOS app, check out <a href="/add-to-app">Add Flutter to existing app</a>.</p></div></aside><p>Use this guide as a cookbook. Jump around and find questions that address your most relevant needs.</p><div class="header-wrapper"><h2 id="overview">Overview</h2><a class="heading-link" href="#overview" aria-label="Link to 'Overview' section">#</a></div><p>As an introduction, watch the following video. It outlines how Flutter works on iOS and how to use Flutter to build iOS apps.</p><iframe class="full-width" src="https://www.youtube.com/embed/ceMsPBbcEGg" title="Flutter for iOS developers" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen loading="lazy"></iframe><br><p><a href="https://www.youtube.com/watch/ceMsPBbcEGg" target="_blank" rel="noopener" title="Open 'Flutter for iOS developers' video in new tab">Flutter for iOS developers</a></p><div class="header-wrapper"><h3 id="views-vs-widgets">Views vs. Widgets</h3><a class="heading-link" href="#views-vs-widgets" aria-label="Link to 'Views vs. Widgets' section">#</a></div><aside class="alert alert-secondary"><div class="alert-header"><span></span></div><div class="alert-content"><p>How is react-style, or <em>declarative</em>, programming different from the traditional imperative style? For a comparison, see <a href="/get-started/flutter-for/declarative">Introduction to declarative UI</a>.</p></div></aside><p>In UIKit, most of what you create in the UI is done using view objects, which are instances of the <code>UIView</code> class. These can act as containers for other <code>UIView</code> classes, which form your layout.</p><p>In Flutter, the rough equivalent to a <code>UIView</code> is a <code>Widget</code>. Widgets don't map exactly to iOS views, but while you're getting acquainted with how Flutter works you can think of them as "the way you declare and construct UI".</p><p>However, these have a few differences to a <code>UIView</code>. To start, widgets have a different lifespan: they are immutable and only exist until they need to be changed. Whenever widgets or their state change, Flutter's framework creates a new tree of widget instances. In comparison, a UIKit view is not recreated when it changes, but rather it's a mutable entity that is drawn once and doesn't redraw until it is invalidated using <code>setNeedsDisplay()</code>.</p><p>Furthermore, unlike <code>UIView</code>, Flutter's widgets are lightweight, in part due to their immutability. Because they aren't views themselves, and aren't directly drawing anything, but rather are a description of the UI and its semantics that get "inflated" into actual view objects under the hood.</p><p>Flutter includes the <a href="https://m3.material.io/develop/flutter/">Material Components</a> library. These are widgets that implement the <a href="https://m3.material.io/styles/">Material Design guidelines</a>. Material Design is a flexible design system <a href="https://m2.material.io/design/platform-guidance/cross-platform-adaptation.html#cross-platform-guidelines">optimized for all platforms</a>, including iOS.</p><p>But Flutter is flexible and expressive enough to implement any design language. On iOS, you can use the <a href="/ui/widgets/cupertino">Cupertino widgets</a> library to produce an interface that looks like <a href="https://developer.apple.com/design/resources">Apple's iOS design language</a>.</p><div class="header-wrapper"><h3 id="updating-widgets">Updating widgets</h3><a class="heading-link" href="#updating-widgets" aria-label="Link to 'Updating widgets' section">#</a></div><p>To update your views in UIKit, you directly mutate them. In Flutter, widgets are immutable and not updated directly. Instead, you have to manipulate the widget's state.</p><p>This is where the concept of Stateful vs Stateless widgets comes in. A <code>StatelessWidget</code> is just what it sounds like—a widget with no state attached.</p><p><code>StatelessWidgets</code> are useful when the part of the user interface you are describing does not depend on anything other than the initial configuration information in the widget.</p><p>For example, with UIKit, this is similar to placing a <code>UIImageView</code> with your logo as the <code>image</code>. If the logo is not changing during runtime, use a <code>StatelessWidget</code> in Flutter.</p><p>If you want to dynamically change the UI based on data received after making an HTTP call, use a <code>StatefulWidget</code>. After the HTTP call has completed, tell the Flutter framework that the widget's <code>State</code> is updated, so it can update the UI.</p><p>The important difference between stateless and stateful widgets is that <code>StatefulWidget</code>s have a <code>State</code> object that stores state data and carries it over across tree rebuilds, so it's not lost.</p><p>If you are in doubt, remember this rule: if a widget changes outside of the <code>build</code> method (because of runtime user interactions, for example), it's stateful. If the widget never changes, once built, it's stateless. However, even if a widget is stateful, the containing parent widget can still be stateless if it isn't itself reacting to those changes (or other inputs).</p><p>The following example shows how to use a <code>StatelessWidget</code>. A common<code>StatelessWidget</code> is the <code>Text</code> widget. If you look at the implementation of the <code>Text</code> widget, you'll find it subclasses <code>StatelessWidget</code>.</p> <?code-excerpt "lib/text_widget.dart (text-widget)" replace="/return const //g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Text</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#0C7064"> 'I like Flutter!'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> style: </span><span style="color:#0468D7">TextStyle</span><span style="color:#222222">(fontWeight: </span><span style="color:#0468D7">FontWeight</span><span style="color:#222222">.bold),</span></span> <span class="line"><span style="color:#222222">);</span></span></code></pre></div></div><p>If you look at the code above, you might notice that the <code>Text</code> widget carries no explicit state with it. It renders what is passed in its constructors and nothing more.</p><p>But, what if you want to make "I Like Flutter" change dynamically, for example when clicking a <code>FloatingActionButton</code>?</p><p>To achieve this, wrap the <code>Text</code> widget in a <code>StatefulWidget</code> and update it when the user clicks the button.</p><p>For example:</p> <?code-excerpt "lib/text_widget.dart (stateful-widget)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#6E6E70"> // Default placeholder text</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222"> textToShow = </span><span style="color:#0C7064">'I Like Flutter'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _updateText</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#6E6E70"> // Update the text</span></span> <span class="line"><span style="color:#222222"> textToShow = </span><span style="color:#0C7064">'Flutter is Awesome!'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">)),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(textToShow)),</span></span> <span class="line"><span style="color:#222222"> floatingActionButton: </span><span style="color:#0468D7">FloatingActionButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: _updateText,</span></span> <span class="line"><span style="color:#222222"> tooltip: </span><span style="color:#0C7064">'Update Text'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span><span style="color:#0468D7">Icons</span><span style="color:#222222">.update),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="widget-layout">Widget layout</h3><a class="heading-link" href="#widget-layout" aria-label="Link to 'Widget layout' section">#</a></div><p>In UIKit, you might use a Storyboard file to organize your views and set constraints, or you might set your constraints programmatically in your view controllers. In Flutter, declare your layout in code by composing a widget tree.</p><p>The following example shows how to display a simple widget with padding:</p> <?code-excerpt "lib/layout.dart (simple-widget)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">@override</span></span> <span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">)),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">CupertinoButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: () {},</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">only</span><span style="color:#222222">(left: </span><span style="color:#0C7064">10</span><span style="color:#222222">, right: </span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Hello'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>You can add padding to any widget, which mimics the functionality of constraints in iOS.</p><p>You can view the layouts that Flutter has to offer in the <a href="/ui/widgets/layout">widget catalog</a>.</p><div class="header-wrapper"><h3 id="removing-widgets">Removing Widgets</h3><a class="heading-link" href="#removing-widgets" aria-label="Link to 'Removing Widgets' section">#</a></div><p>In UIKit, you call <code>addSubview()</code> on the parent, or <code>removeFromSuperview()</code> on a child view to dynamically add or remove child views. In Flutter, because widgets are immutable, there is no direct equivalent to <code>addSubview()</code>. Instead, you can pass a function to the parent that returns a widget, and control that child's creation with a boolean flag.</p><p>The following example shows how to toggle between two widgets when the user clicks the <code>FloatingActionButton</code>:</p> <?code-excerpt "lib/layout.dart (toggle-widget)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#6E6E70"> // Default value for toggle.</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#222222"> toggle = </span><span style="color:#0C7064">true</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> _toggle</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> toggle = !toggle;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> _getToggleChild</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (toggle) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Toggle One'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> CupertinoButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: () {},</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Toggle Two'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#6200EE">_getToggleChild</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> floatingActionButton: </span><span style="color:#0468D7">FloatingActionButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: _toggle,</span></span> <span class="line"><span style="color:#222222"> tooltip: </span><span style="color:#0C7064">'Update Text'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span><span style="color:#0468D7">Icons</span><span style="color:#222222">.update),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="animations">Animations</h3><a class="heading-link" href="#animations" aria-label="Link to 'Animations' section">#</a></div><p>In UIKit, you create an animation by calling the <code>animate(withDuration:animations:)</code> method on a view. In Flutter, use the animation library to wrap widgets inside an animated widget.</p><p>In Flutter, use an <code>AnimationController</code>, which is an <code>Animation<double></code> that can pause, seek, stop, and reverse the animation. It requires a <code>Ticker</code> that signals when vsync happens and produces a linear interpolation between 0 and 1 on each frame while it's running. You then create one or more <code>Animation</code>s and attach them to the controller.</p><p>For example, you might use <code>CurvedAnimation</code> to implement an animation along an interpolated curve. In this sense, the controller is the "master" source of the animation progress and the <code>CurvedAnimation</code> computes the curve that replaces the controller's default linear motion. Like widgets, animations in Flutter work with composition.</p><p>When building the widget tree you assign the <code>Animation</code> to an animated property of a widget, such as the opacity of a <code>FadeTransition</code>, and tell the controller to start the animation.</p><p>The following example shows how to write a <code>FadeTransition</code> that fades the widget into a logo when you press the <code>FloatingActionButton</code>:</p> <?code-excerpt "lib/animation.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Fade Demo'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">MyFadeTest</span><span style="color:#222222">(title: </span><span style="color:#0C7064">'Fade Demo'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> MyFadeTest</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MyFadeTest</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key, </span><span style="color:#BD2314">required</span><span style="color:#BD2314"> this</span><span style="color:#222222">.title});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> title;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">MyFadeTest</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_MyFadeTest</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _MyFadeTest</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">MyFadeTest</span><span style="color:#222222">></span></span> <span class="line"><span style="color:#BD2314"> with</span><span style="color:#0468D7"> SingleTickerProviderStateMixin</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> late</span><span style="color:#0468D7"> AnimationController</span><span style="color:#222222"> controller;</span></span> <span class="line"><span style="color:#BD2314"> late</span><span style="color:#0468D7"> CurvedAnimation</span><span style="color:#222222"> curve;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> controller = </span><span style="color:#0468D7">AnimationController</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> duration: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Duration</span><span style="color:#222222">(milliseconds: </span><span style="color:#0C7064">2000</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> vsync: </span><span style="color:#BD2314">this</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> curve = </span><span style="color:#0468D7">CurvedAnimation</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> parent: controller,</span></span> <span class="line"><span style="color:#222222"> curve: </span><span style="color:#0468D7">Curves</span><span style="color:#222222">.easeIn,</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> dispose</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#222222"> controller.</span><span style="color:#6200EE">dispose</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">dispose</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(title: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(widget.title)),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">FadeTransition</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> opacity: curve,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> FlutterLogo</span><span style="color:#222222">(size: </span><span style="color:#0C7064">100</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> floatingActionButton: </span><span style="color:#0468D7">FloatingActionButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: () {</span></span> <span class="line"><span style="color:#222222"> controller.</span><span style="color:#6200EE">forward</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> tooltip: </span><span style="color:#0C7064">'Fade'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span><span style="color:#0468D7">Icons</span><span style="color:#222222">.brush),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>For more information, see <a href="/ui/widgets/animation">Animation & Motion widgets</a>, the <a href="/ui/animations/tutorial">Animations tutorial</a>, and the <a href="/ui/animations">Animations overview</a>.</p><div class="header-wrapper"><h3 id="drawing-on-the-screen">Drawing on the screen</h3><a class="heading-link" href="#drawing-on-the-screen" aria-label="Link to 'Drawing on the screen' section">#</a></div><p>In UIKit, you use <code>CoreGraphics</code> to draw lines and shapes to the screen. Flutter has a different API based on the <code>Canvas</code> class, with two other classes that help you draw: <code>CustomPaint</code> and <code>CustomPainter</code>, the latter of which implements your algorithm to draw to the canvas.</p><p>To learn how to implement a signature painter in Flutter, see Collin's answer on <a href="https://stackoverflow.com/questions/46241071/create-signature-area-for-mobile-app-in-dart-flutter">StackOverflow</a>.</p> <?code-excerpt "lib/canvas.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() => </span><span style="color:#6200EE">runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(home: </span><span style="color:#0468D7">DemoApp</span><span style="color:#222222">()));</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> DemoApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> DemoApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) => </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(body: </span><span style="color:#0468D7">Signature</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> Signature</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> Signature</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">Signature</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">SignatureState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SignatureState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">Signature</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Offset</span><span style="color:#222222">?> _points = <</span><span style="color:#0468D7">Offset</span><span style="color:#222222">?>[];</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPanUpdate: (details) {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#0468D7"> RenderBox</span><span style="color:#222222">? referenceBox = context.</span><span style="color:#6200EE">findRenderObject</span><span style="color:#222222">() </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> RenderBox</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#0468D7"> Offset</span><span style="color:#222222"> localPosition =</span></span> <span class="line"><span style="color:#222222"> referenceBox.</span><span style="color:#6200EE">globalToLocal</span><span style="color:#222222">(details.globalPosition);</span></span> <span class="line"><span style="color:#222222"> _points = </span><span style="color:#0468D7">List</span><span style="color:#222222">.</span><span style="color:#6200EE">from</span><span style="color:#222222">(_points)..</span><span style="color:#6200EE">add</span><span style="color:#222222">(localPosition);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> onPanEnd: (details) => _points.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#0C7064">null</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">CustomPaint</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> painter: </span><span style="color:#0468D7">SignaturePainter</span><span style="color:#222222">(_points),</span></span> <span class="line"><span style="color:#222222"> size: </span><span style="color:#0468D7">Size</span><span style="color:#222222">.infinite,</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SignaturePainter</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> CustomPainter</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> SignaturePainter</span><span style="color:#222222">(</span><span style="color:#BD2314">this</span><span style="color:#222222">.points);</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Offset</span><span style="color:#222222">?> points;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> paint</span><span style="color:#222222">(</span><span style="color:#0468D7">Canvas</span><span style="color:#222222"> canvas, </span><span style="color:#0468D7">Size</span><span style="color:#222222"> size) {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Paint</span><span style="color:#222222"> paint = </span><span style="color:#0468D7">Paint</span><span style="color:#222222">()</span></span> <span class="line"><span style="color:#222222"> ..color = </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.black</span></span> <span class="line"><span style="color:#222222"> ..strokeCap = </span><span style="color:#0468D7">StrokeCap</span><span style="color:#222222">.round</span></span> <span class="line"><span style="color:#222222"> ..strokeWidth = </span><span style="color:#0C7064">5</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#0468D7">int</span><span style="color:#222222"> i = </span><span style="color:#0C7064">0</span><span style="color:#222222">; i < points.length - </span><span style="color:#0C7064">1</span><span style="color:#222222">; i++) {</span></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (points[i] != </span><span style="color:#0C7064">null</span><span style="color:#222222"> && points[i + </span><span style="color:#0C7064">1</span><span style="color:#222222">] != </span><span style="color:#0C7064">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> canvas.</span><span style="color:#6200EE">drawLine</span><span style="color:#222222">(points[i]!, points[i + </span><span style="color:#0C7064">1</span><span style="color:#222222">]!, paint);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#6200EE"> shouldRepaint</span><span style="color:#222222">(</span><span style="color:#0468D7">SignaturePainter</span><span style="color:#222222"> oldDelegate) =></span></span> <span class="line"><span style="color:#222222"> oldDelegate.points != points;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="widget-opacity">Widget opacity</h3><a class="heading-link" href="#widget-opacity" aria-label="Link to 'Widget opacity' section">#</a></div><p>In UIKit, everything has <code>.opacity</code> or <code>.alpha</code>. In Flutter, most of the time you need to wrap a widget in an <code>Opacity</code> widget to accomplish this.</p><div class="header-wrapper"><h3 id="custom-widgets">Custom Widgets</h3><a class="heading-link" href="#custom-widgets" aria-label="Link to 'Custom Widgets' section">#</a></div><p>In UIKit, you typically subclass <code>UIView</code>, or use a pre-existing view, to override and implement methods that achieve the desired behavior. In Flutter, build a custom widget by <a href="/resources/architectural-overview#composition">composing</a> smaller widgets (instead of extending them).</p><p>For example, how do you build a <code>CustomButton</code> that takes a label in the constructor? Create a CustomButton that composes a <code>ElevatedButton</code> with a label, rather than by extending <code>ElevatedButton</code>:</p> <?code-excerpt "lib/custom.dart (custom-button)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> CustomButton</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> CustomButton</span><span style="color:#222222">(</span><span style="color:#BD2314">this</span><span style="color:#222222">.label, {</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> label;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> ElevatedButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: () {},</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(label),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Then use <code>CustomButton</code>, just as you'd use any other Flutter widget:</p> <?code-excerpt "lib/custom.dart (use-custom-button)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">@override</span></span> <span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">CustomButton</span><span style="color:#222222">(</span><span style="color:#0C7064">'Hello'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="managing-dependencies">Managing dependencies</h3><a class="heading-link" href="#managing-dependencies" aria-label="Link to 'Managing dependencies' section">#</a></div><p>In iOS, you add dependencies with CocoaPods by adding to your <code>Podfile</code>. Flutter uses Dart's build system and the Pub package manager to handle dependencies. The tools delegate the building of the native Android and iOS wrapper apps to the respective build systems.</p><p>While there is a Podfile in the iOS folder in your Flutter project, only use this if you are adding native dependencies needed for per-platform integration. In general, use <code>pubspec.yaml</code> to declare external dependencies in Flutter. A good place to find great packages for Flutter is on <a href="https://pub.dev/flutter/packages">pub.dev</a>.</p><div class="header-wrapper"><h2 id="navigation">Navigation</h2><a class="heading-link" href="#navigation" aria-label="Link to 'Navigation' section">#</a></div><p>This section of the document discusses navigation between pages of an app, the push and pop mechanism, and more.</p><div class="header-wrapper"><h3 id="navigating-between-pages">Navigating between pages</h3><a class="heading-link" href="#navigating-between-pages" aria-label="Link to 'Navigating between pages' section">#</a></div><p>In UIKit, to travel between view controllers, you can use a <code>UINavigationController</code> that manages the stack of view controllers to display.</p><p>Flutter has a similar implementation, using a <code>Navigator</code> and <code>Routes</code>. A <code>Route</code> is an abstraction for a "screen" or "page" of an app, and a <code>Navigator</code> is a <a href="/resources/architectural-overview#widgets">widget</a> that manages routes. A route roughly maps to a <code>UIViewController</code>. The navigator works in a similar way to the iOS <code>UINavigationController</code>, in that it can <code>push()</code> and <code>pop()</code> routes depending on whether you want to navigate to, or back from, a view.</p><p>To navigate between pages, you have a couple options:</p><ul><li>Specify a <code>Map</code> of route names.</li><li>Directly navigate to a route.</li></ul><p>The following example builds a <code>Map.</code></p> <?code-excerpt "lib/intent.dart (map)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#0468D7"> CupertinoApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> MyAppHome</span><span style="color:#222222">(), </span><span style="color:#6E6E70">// becomes the route named '/'</span></span> <span class="line"><span style="color:#222222"> routes: <</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">WidgetBuilder</span><span style="color:#222222">>{</span></span> <span class="line"><span style="color:#0C7064"> '/a'</span><span style="color:#222222">: (context) => </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> MyPage</span><span style="color:#222222">(title: </span><span style="color:#0C7064">'page A'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#0C7064"> '/b'</span><span style="color:#222222">: (context) => </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> MyPage</span><span style="color:#222222">(title: </span><span style="color:#0C7064">'page B'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#0C7064"> '/c'</span><span style="color:#222222">: (context) => </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> MyPage</span><span style="color:#222222">(title: </span><span style="color:#0C7064">'page C'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Navigate to a route by <code>push</code>ing its name to the <code>Navigator</code>.</p> <?code-excerpt "lib/intent.dart (push)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Navigator</span><span style="color:#222222">.</span><span style="color:#6200EE">of</span><span style="color:#222222">(context).</span><span style="color:#6200EE">pushNamed</span><span style="color:#222222">(</span><span style="color:#0C7064">'/b'</span><span style="color:#222222">);</span></span></code></pre></div></div><p>The <code>Navigator</code> class handles routing in Flutter and is used to get a result back from a route that you have pushed on the stack. This is done by <code>await</code>ing on the <code>Future</code> returned by <code>push()</code>.</p><p>For example, to start a <code>location</code> route that lets the user select their location, you might do the following:</p> <?code-excerpt "lib/intent.dart (push-await)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Object</span><span style="color:#222222">? coordinates = </span><span style="color:#BD2314">await</span><span style="color:#0468D7"> Navigator</span><span style="color:#222222">.</span><span style="color:#6200EE">of</span><span style="color:#222222">(context).</span><span style="color:#6200EE">pushNamed</span><span style="color:#222222">(</span><span style="color:#0C7064">'/location'</span><span style="color:#222222">);</span></span></code></pre></div></div><p>And then, inside your <code>location</code> route, once the user has selected their location, <code>pop()</code> the stack with the result:</p> <?code-excerpt "lib/intent.dart (pop)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Navigator</span><span style="color:#222222">.</span><span style="color:#6200EE">of</span><span style="color:#222222">(context).</span><span style="color:#6200EE">pop</span><span style="color:#222222">({</span><span style="color:#0C7064">'lat'</span><span style="color:#222222">: </span><span style="color:#0C7064">43.821757</span><span style="color:#222222">, </span><span style="color:#0C7064">'long'</span><span style="color:#222222">: -</span><span style="color:#0C7064">79.226392</span><span style="color:#222222">});</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="navigating-to-another-app">Navigating to another app</h3><a class="heading-link" href="#navigating-to-another-app" aria-label="Link to 'Navigating to another app' section">#</a></div><p>In UIKit, to send the user to another application, you use a specific URL scheme. For the system level apps, the scheme depends on the app. To implement this functionality in Flutter, create a native platform integration, or use an <a href="https://pub.dev/flutter">existing plugin</a>, such as <a href="https://pub.dev/packages/url_launcher"><code>url_launcher</code></a>.</p><div class="header-wrapper"><h3 id="manually-pop-back">Manually pop back</h3><a class="heading-link" href="#manually-pop-back" aria-label="Link to 'Manually pop back' section">#</a></div><p>Calling <code>SystemNavigator.pop()</code> from your Dart code invokes the following iOS code:</p><div class="code-block-wrapper language-objc"><div class="code-block-body"><span class="code-block-language" title="Language objc">objc</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">UIViewController* viewController = [UIApplication </span><span style="color:#6200EE">sharedApplication</span><span style="color:#222222">].keyWindow.rootViewController;</span></span> <span class="line"><span style="color:#BD2314">if</span><span style="color:#222222"> ([viewController </span><span style="color:#6200EE">isKindOfClass</span><span style="color:#222222">:[UINavigationController </span><span style="color:#6200EE">class</span><span style="color:#222222">]]) {</span></span> <span class="line"><span style="color:#222222"> [((UINavigationController*)viewController) </span><span style="color:#6200EE">popViewControllerAnimated</span><span style="color:#222222">:</span><span style="color:#0C7064">NO</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>If that doesn't do what you want, you can create your own <a href="/platform-integration/platform-channels">platform channel</a> to invoke arbitrary iOS code.</p><div class="header-wrapper"><h3 id="handling-localization">Handling localization</h3><a class="heading-link" href="#handling-localization" aria-label="Link to 'Handling localization' section">#</a></div><p>Unlike iOS, which has the <code>Localizable.strings</code> file, Flutter doesn't currently have a dedicated system for handling strings. At the moment, the best practice is to declare your copy text in a class as static fields and access them from there. For example:</p> <?code-excerpt "lib/string_examples.dart (strings)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> Strings</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> static</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> String</span><span style="color:#222222"> welcomeMessage = </span><span style="color:#0C7064">'Welcome To Flutter'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>You can access your strings as such:</p> <?code-excerpt "lib/string_examples.dart (access-string)" replace="/const //g; /return //g;"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0468D7">Strings</span><span style="color:#222222">.welcomeMessage);</span></span></code></pre></div></div><p>By default, Flutter only supports US English for its strings. If you need to add support for other languages, include the <code>flutter_localizations</code> package. You might also need to add Dart's <a href="https://pub.dev/packages/intl"><code>intl</code></a> package to use i10n machinery, such as date/time formatting.</p><div class="code-block-wrapper language-yaml"><div class="code-block-body"><span class="code-block-language" title="Language yaml">yaml</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">dependencies</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#0468D7"> flutter_localizations</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#0468D7"> sdk</span><span style="color:#222222">: </span><span style="color:#0C7064">flutter</span></span> <span class="line"><span style="color:#0468D7"> intl</span><span style="color:#222222">: </span><span style="color:#0C7064">any</span><span style="color:#6E6E70"> # Use version of intl from flutter_localizations.</span></span></code></pre></div></div><p>To use the <code>flutter_localizations</code> package, specify the <code>localizationsDelegates</code> and <code>supportedLocales</code> on the app widget:</p> <?code-excerpt "lib/localizations_example.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter_localizations/flutter_localizations.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> MyWidget</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MyWidget</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> localizationsDelegates: <</span><span style="color:#0468D7">LocalizationsDelegate</span><span style="color:#222222"><</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>[</span></span> <span class="line"><span style="color:#6E6E70"> // Add app-specific localization delegate[s] here</span></span> <span class="line"><span style="color:#0468D7"> GlobalMaterialLocalizations</span><span style="color:#222222">.delegate,</span></span> <span class="line"><span style="color:#0468D7"> GlobalWidgetsLocalizations</span><span style="color:#222222">.delegate,</span></span> <span class="line"><span style="color:#222222"> ],</span></span> <span class="line"><span style="color:#222222"> supportedLocales: <</span><span style="color:#0468D7">Locale</span><span style="color:#222222">>[</span></span> <span class="line"><span style="color:#0468D7"> Locale</span><span style="color:#222222">(</span><span style="color:#0C7064">'en'</span><span style="color:#222222">, </span><span style="color:#0C7064">'US'</span><span style="color:#222222">), </span><span style="color:#6E6E70">// English</span></span> <span class="line"><span style="color:#0468D7"> Locale</span><span style="color:#222222">(</span><span style="color:#0C7064">'he'</span><span style="color:#222222">, </span><span style="color:#0C7064">'IL'</span><span style="color:#222222">), </span><span style="color:#6E6E70">// Hebrew</span></span> <span class="line"><span style="color:#6E6E70"> // ... other locales the app supports</span></span> <span class="line"><span style="color:#222222"> ],</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The delegates contain the actual localized values, while the <code>supportedLocales</code> defines which locales the app supports. The above example uses a <code>MaterialApp</code>, so it has both a <code>GlobalWidgetsLocalizations</code> for the base widgets localized values, and a <code>MaterialWidgetsLocalizations</code> for the Material widgets localizations. If you use <code>WidgetsApp</code> for your app, you don't need the latter. Note that these two delegates contain "default" values, but you'll need to provide one or more delegates for your own app's localizable copy, if you want those to be localized too.</p><p>When initialized, the <code>WidgetsApp</code> (or <code>MaterialApp</code>) creates a <a href="https://api.flutter.dev/flutter/widgets/Localizations-class.html"><code>Localizations</code></a> widget for you, with the delegates you specify. The current locale for the device is always accessible from the <code>Localizations</code> widget from the current context (in the form of a <code>Locale</code> object), or using the <a href="https://api.flutter.dev/flutter/dart-ui/Window/locale.html"><code>Window.locale</code></a>.</p><p>To access localized resources, use the <code>Localizations.of()</code> method to access a specific localizations class that is provided by a given delegate. Use the <a href="https://pub.dev/packages/intl_translation"><code>intl_translation</code></a> package to extract translatable copy to <a href="https://github.com/googlei18n/app-resource-bundle">arb</a> files for translating, and importing them back into the app for using them with <code>intl</code>.</p><p>For further details on internationalization and localization in Flutter, see the <a href="/ui/accessibility-and-internationalization/internationalization">internationalization guide</a>, which has sample code with and without the <code>intl</code> package.</p><div class="header-wrapper"><h2 id="viewcontrollers">ViewControllers</h2><a class="heading-link" href="#viewcontrollers" aria-label="Link to 'ViewControllers' section">#</a></div><p>This section of the document discusses the equivalent of ViewController in Flutter and how to listen to lifecycle events.</p><div class="header-wrapper"><h3 id="equivalent-of-viewcontroller-in-flutter">Equivalent of ViewController in Flutter</h3><a class="heading-link" href="#equivalent-of-viewcontroller-in-flutter" aria-label="Link to 'Equivalent of ViewController in Flutter' section">#</a></div><p>In UIKit, a <code>ViewController</code> represents a portion of user interface, most commonly used for a screen or section. These are composed together to build complex user interfaces, and help scale your application's UI. In Flutter, this job falls to Widgets. As mentioned in the Navigation section, screens in Flutter are represented by Widgets since "everything is a widget!" Use a <code>Navigator</code> to move between different <code>Route</code>s that represent different screens or pages, or maybe different states or renderings of the same data.</p><div class="header-wrapper"><h3 id="listening-to-lifecycle-events">Listening to lifecycle events</h3><a class="heading-link" href="#listening-to-lifecycle-events" aria-label="Link to 'Listening to lifecycle events' section">#</a></div><p>In UIKit, you can override methods to the <code>ViewController</code> to capture lifecycle methods for the view itself, or register lifecycle callbacks in the <code>AppDelegate</code>. In Flutter, you have neither concept, but you can instead listen to lifecycle events by hooking into the <code>WidgetsBinding</code> observer and listening to the <code>didChangeAppLifecycleState()</code> change event.</p><p>The observable lifecycle events are:</p><dl><dt><strong><code>inactive</code></strong></dt><dd>The application is in an inactive state and is not receiving user input. This event only works on iOS, as there is no equivalent event on Android.</dd><dt><strong><code>paused</code></strong></dt><dd>The application is not currently visible to the user, is not responding to user input, but is running in the background.</dd><dt><strong><code>resumed</code></strong></dt><dd>The application is visible and responding to user input.</dd><dt><strong><code>suspending</code></strong></dt><dd>The application is suspended momentarily. The iOS platform has no equivalent event.</dd></dl><p>For more details on the meaning of these states, see <a href="https://api.flutter.dev/flutter/dart-ui/AppLifecycleState.html"><code>AppLifecycleState</code> documentation</a>.</p><div class="header-wrapper"><h2 id="layouts">Layouts</h2><a class="heading-link" href="#layouts" aria-label="Link to 'Layouts' section">#</a></div><p>This section discusses different layouts in Flutter and how they compare with UIKit.</p><div class="header-wrapper"><h3 id="displaying-a-list-view">Displaying a list view</h3><a class="heading-link" href="#displaying-a-list-view" aria-label="Link to 'Displaying a list view' section">#</a></div><p>In UIKit, you might show a list in either a <code>UITableView</code> or a <code>UICollectionView</code>. In Flutter, you have a similar implementation using a <code>ListView</code>. In UIKit, these views have delegate methods for deciding the number of rows, the cell for each index path, and the size of the cells.</p><p>Due to Flutter's immutable widget pattern, you pass a list of widgets to your <code>ListView</code>, and Flutter takes care of making sure that scrolling is fast and smooth.</p> <?code-excerpt "lib/listview.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Widget</span><span style="color:#222222">> </span><span style="color:#6200EE">_getListData</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Widget</span><span style="color:#222222">> widgets = [];</span></span> <span class="line"><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#0468D7">int</span><span style="color:#222222"> i = </span><span style="color:#0C7064">0</span><span style="color:#222222">; i < </span><span style="color:#0C7064">100</span><span style="color:#222222">; i++) {</span></span> <span class="line"><span style="color:#222222"> widgets.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#0468D7">Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row </span><span style="color:#0C7064">$</span><span style="color:#222222">i</span><span style="color:#0C7064">'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ));</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#222222"> widgets;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">ListView</span><span style="color:#222222">(children: </span><span style="color:#6200EE">_getListData</span><span style="color:#222222">()),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="detecting-what-was-clicked">Detecting what was clicked</h3><a class="heading-link" href="#detecting-what-was-clicked" aria-label="Link to 'Detecting what was clicked' section">#</a></div><p>In UIKit, you implement the delegate method, <code>tableView:didSelectRowAtIndexPath:</code>. In Flutter, use the touch handling provided by the passed-in widgets.</p> <?code-excerpt "lib/list_item_tapped.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:developer'</span><span style="color:#BD2314"> as</span><span style="color:#222222"> developer;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Widget</span><span style="color:#222222">> </span><span style="color:#6200EE">_getListData</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Widget</span><span style="color:#222222">> widgets = [];</span></span> <span class="line"><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#0468D7">int</span><span style="color:#222222"> i = </span><span style="color:#0C7064">0</span><span style="color:#222222">; i < </span><span style="color:#0C7064">100</span><span style="color:#222222">; i++) {</span></span> <span class="line"><span style="color:#222222"> widgets.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTap: () {</span></span> <span class="line"><span style="color:#222222"> developer.</span><span style="color:#6200EE">log</span><span style="color:#222222">(</span><span style="color:#0C7064">'row tapped'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row </span><span style="color:#0C7064">$</span><span style="color:#222222">i</span><span style="color:#0C7064">'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#222222"> widgets;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">ListView</span><span style="color:#222222">(children: </span><span style="color:#6200EE">_getListData</span><span style="color:#222222">()),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dynamically-updating-listview">Dynamically updating ListView</h3><a class="heading-link" href="#dynamically-updating-listview" aria-label="Link to 'Dynamically updating ListView' section">#</a></div><p>In UIKit, you update the data for the list view, and notify the table or collection view using the <code>reloadData</code> method.</p><p>In Flutter, if you update the list of widgets inside a <code>setState()</code>, you quickly see that your data doesn't change visually. This is because when <code>setState()</code> is called, the Flutter rendering engine looks at the widget tree to see if anything has changed. When it gets to your <code>ListView</code>, it performs an <code>==</code> check, and determines that the two <code>ListView</code>s are the same. Nothing has changed, so no update is required.</p><p>For a simple way to update your <code>ListView</code>, create a new <code>List</code> inside of <code>setState()</code>, and copy the data from the old list to the new list. While this approach is simple, it is not recommended for large data sets, as shown in the next example.</p> <?code-excerpt "lib/listview_dynamic.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:developer'</span><span style="color:#BD2314"> as</span><span style="color:#222222"> developer;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Widget</span><span style="color:#222222">> widgets = <</span><span style="color:#0468D7">Widget</span><span style="color:#222222">>[];</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#0468D7">int</span><span style="color:#222222"> i = </span><span style="color:#0C7064">0</span><span style="color:#222222">; i < </span><span style="color:#0C7064">100</span><span style="color:#222222">; i++) {</span></span> <span class="line"><span style="color:#222222"> widgets.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#6200EE">getRow</span><span style="color:#222222">(i));</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> i) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTap: () {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> widgets = </span><span style="color:#0468D7">List</span><span style="color:#222222">.</span><span style="color:#6200EE">from</span><span style="color:#222222">(widgets);</span></span> <span class="line"><span style="color:#222222"> widgets.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#6200EE">getRow</span><span style="color:#222222">(widgets.length));</span></span> <span class="line"><span style="color:#222222"> developer.</span><span style="color:#6200EE">log</span><span style="color:#222222">(</span><span style="color:#0C7064">'row </span><span style="color:#0C7064">$</span><span style="color:#222222">i</span><span style="color:#0C7064">'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row </span><span style="color:#0C7064">$</span><span style="color:#222222">i</span><span style="color:#0C7064">'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">ListView</span><span style="color:#222222">(children: widgets),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The recommended, efficient, and effective way to build a list uses a <code>ListView.Builder</code>. This method is great when you have a dynamic list or a list with very large amounts of data.</p> <?code-excerpt "lib/listview_builder.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:developer'</span><span style="color:#BD2314"> as</span><span style="color:#222222"> developer;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Widget</span><span style="color:#222222">> widgets = [];</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#0468D7">int</span><span style="color:#222222"> i = </span><span style="color:#0C7064">0</span><span style="color:#222222">; i < </span><span style="color:#0C7064">100</span><span style="color:#222222">; i++) {</span></span> <span class="line"><span style="color:#222222"> widgets.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#6200EE">getRow</span><span style="color:#222222">(i));</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> i) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTap: () {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> widgets.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#6200EE">getRow</span><span style="color:#222222">(widgets.length));</span></span> <span class="line"><span style="color:#222222"> developer.</span><span style="color:#6200EE">log</span><span style="color:#222222">(</span><span style="color:#0C7064">'row </span><span style="color:#0C7064">$</span><span style="color:#222222">i</span><span style="color:#0C7064">'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row </span><span style="color:#0C7064">$</span><span style="color:#222222">i</span><span style="color:#0C7064">'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">ListView</span><span style="color:#222222">.</span><span style="color:#6200EE">builder</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> itemCount: widgets.length,</span></span> <span class="line"><span style="color:#222222"> itemBuilder: (context, position) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(position);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Instead of creating a <code>ListView</code>, create a <code>ListView.builder</code> that takes two key parameters: the initial length of the list, and an <code>ItemBuilder</code> function.</p><p>The <code>ItemBuilder</code> function is similar to the <code>cellForItemAt</code> delegate method in an iOS table or collection view, as it takes a position, and returns the cell you want rendered at that position.</p><p>Finally, but most importantly, notice that the <code>onTap()</code> function doesn't recreate the list anymore, but instead <code>.add</code>s to it.</p><div class="header-wrapper"><h3 id="creating-a-scroll-view">Creating a scroll view</h3><a class="heading-link" href="#creating-a-scroll-view" aria-label="Link to 'Creating a scroll view' section">#</a></div><p>In UIKit, you wrap your views in a <code>ScrollView</code> that allows a user to scroll your content if needed.</p><p>In Flutter the easiest way to do this is using the <code>ListView</code> widget. This acts as both a <code>ScrollView</code> and an iOS <code>TableView</code>, as you can lay out widgets in a vertical format.</p> <?code-excerpt "lib/layout.dart (list-view)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">@override</span></span> <span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> ListView</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> children: </span><span style="color:#BD2314">const</span><span style="color:#222222"> <</span><span style="color:#0468D7">Widget</span><span style="color:#222222">>[</span></span> <span class="line"><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row One'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row Two'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row Three'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row Four'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ],</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>For more detailed docs on how to lay out widgets in Flutter, see the <a href="/ui/widgets/layout">layout tutorial</a>.</p><div class="header-wrapper"><h2 id="gesture-detection-and-touch-event-handling">Gesture detection and touch event handling</h2><a class="heading-link" href="#gesture-detection-and-touch-event-handling" aria-label="Link to 'Gesture detection and touch event handling' section">#</a></div><p>This section discusses how to detect gestures and handle different events in Flutter, and how they compare with UIKit.</p><div class="header-wrapper"><h3 id="adding-a-click-listener">Adding a click listener</h3><a class="heading-link" href="#adding-a-click-listener" aria-label="Link to 'Adding a click listener' section">#</a></div><p>In UIKit, you attach a <code>GestureRecognizer</code> to a view to handle click events. In Flutter, there are two ways of adding touch listeners:</p><ol><li>If the widget supports event detection, pass a function to it, and handle the event in the function. For example, the <code>ElevatedButton</code> widget has an <code>onPressed</code> parameter:</li></ol> <?code-excerpt "lib/events.dart (on-pressed)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">@override</span></span> <span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> ElevatedButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onPressed: () {</span></span> <span class="line"><span style="color:#222222"> developer.</span><span style="color:#6200EE">log</span><span style="color:#222222">(</span><span style="color:#0C7064">'click'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Button'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><ol start="2"><li>If the Widget doesn't support event detection, wrap the widget in a GestureDetector and pass a function to the <code>onTap</code> parameter.</li></ol> <?code-excerpt "lib/events.dart (on-tap)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleTapApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleTapApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onTap: () {</span></span> <span class="line"><span style="color:#222222"> developer.</span><span style="color:#6200EE">log</span><span style="color:#222222">(</span><span style="color:#0C7064">'tap'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> FlutterLogo</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> size: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="handling-other-gestures">Handling other gestures</h3><a class="heading-link" href="#handling-other-gestures" aria-label="Link to 'Handling other gestures' section">#</a></div><p>Using <code>GestureDetector</code> you can listen to a wide range of gestures such as:</p><ul><li><p><strong>Tapping</strong></p><dl><dt><strong><code>onTapDown</code></strong></dt><dd>A pointer that might cause a tap has contacted the screen at a particular location.</dd><dt><strong><code>onTapUp</code></strong></dt><dd>A pointer that triggers a tap has stopped contacting the screen at a particular location.</dd><dt><strong><code>onTap</code></strong></dt><dd>A tap has occurred.</dd><dt><strong><code>onTapCancel</code></strong></dt><dd>The pointer that previously triggered the <code>onTapDown</code> won't cause a tap.</dd></dl></li><li><p><strong>Double tapping</strong></p><dl><dt><strong><code>onDoubleTap</code></strong></dt><dd>The user tapped the screen at the same location twice in quick succession.</dd></dl></li><li><p><strong>Long pressing</strong></p><dl><dt><strong><code>onLongPress</code></strong></dt><dd>A pointer has remained in contact with the screen at the same location for a long period of time.</dd></dl></li><li><p><strong>Vertical dragging</strong></p><dl><dt><strong><code>onVerticalDragStart</code></strong></dt><dd>A pointer has contacted the screen and might begin to move vertically.</dd><dt><strong><code>onVerticalDragUpdate</code></strong></dt><dd>A pointer in contact with the screen has moved further in the vertical direction.</dd><dt><strong><code>onVerticalDragEnd</code></strong></dt><dd>A pointer that was previously in contact with the screen and moving vertically is no longer in contact with the screen and was moving at a specific velocity when it stopped contacting the screen.</dd></dl></li><li><p><strong>Horizontal dragging</strong></p><dl><dt><strong><code>onHorizontalDragStart</code></strong></dt><dd>A pointer has contacted the screen and might begin to move horizontally.</dd><dt><strong><code>onHorizontalDragUpdate</code></strong></dt><dd>A pointer in contact with the screen has moved further in the horizontal direction.</dd><dt><strong><code>onHorizontalDragEnd</code></strong></dt><dd>A pointer that was previously in contact with the screen and moving horizontally is no longer in contact with the screen.</dd></dl></li></ul><p>The following example shows a <code>GestureDetector</code> that rotates the Flutter logo on a double tap:</p> <?code-excerpt "lib/events.dart (sample-app)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleApp</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleApp</span><span style="color:#222222">></span></span> <span class="line"><span style="color:#BD2314"> with</span><span style="color:#0468D7"> SingleTickerProviderStateMixin</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> late</span><span style="color:#0468D7"> AnimationController</span><span style="color:#222222"> controller;</span></span> <span class="line"><span style="color:#BD2314"> late</span><span style="color:#0468D7"> CurvedAnimation</span><span style="color:#222222"> curve;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> controller = </span><span style="color:#0468D7">AnimationController</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> vsync: </span><span style="color:#BD2314">this</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> duration: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Duration</span><span style="color:#222222">(milliseconds: </span><span style="color:#0C7064">2000</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> curve = </span><span style="color:#0468D7">CurvedAnimation</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> parent: controller,</span></span> <span class="line"><span style="color:#222222"> curve: </span><span style="color:#0468D7">Curves</span><span style="color:#222222">.easeIn,</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">GestureDetector</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onDoubleTap: () {</span></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (controller.isCompleted) {</span></span> <span class="line"><span style="color:#222222"> controller.</span><span style="color:#6200EE">reverse</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#BD2314">else</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#222222"> controller.</span><span style="color:#6200EE">forward</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">RotationTransition</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> turns: curve,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> FlutterLogo</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> size: </span><span style="color:#0C7064">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="themes-styles-and-media">Themes, styles, and media</h2><a class="heading-link" href="#themes-styles-and-media" aria-label="Link to 'Themes, styles, and media' section">#</a></div><p>Flutter applications are easy to style; you can switch between light and dark themes, change the style of your text and UI components, and more. This section covers aspects of styling your Flutter apps and compares how you might do the same in UIKit.</p><div class="header-wrapper"><h3 id="using-a-theme">Using a theme</h3><a class="heading-link" href="#using-a-theme" aria-label="Link to 'Using a theme' section">#</a></div><p>Out of the box, Flutter comes with a beautiful implementation of Material Design, which takes care of a lot of styling and theming needs that you would typically do.</p><p>To take full advantage of Material Components in your app, declare a top-level widget, <code>MaterialApp</code>, as the entry point to your application. <code>MaterialApp</code> is a convenience widget that wraps a number of widgets that are commonly required for applications implementing Material Design. It builds upon a <code>WidgetsApp</code> by adding Material specific functionality.</p><p>But Flutter is flexible and expressive enough to implement any design language. On iOS, you can use the <a href="https://api.flutter.dev/flutter/cupertino/cupertino-library.html">Cupertino library</a> to produce an interface that adheres to the <a href="https://developer.apple.com/ios/human-interface-guidelines/overview/themes/">Human Interface Guidelines</a>. For the full set of these widgets, see the <a href="/ui/widgets/cupertino">Cupertino widgets</a> gallery.</p><p>You can also use a <code>WidgetsApp</code> as your app widget, which provides some of the same functionality, but is not as rich as <code>MaterialApp</code>.</p><p>To customize the colors and styles of any child components, pass a <code>ThemeData</code> object to the <code>MaterialApp</code> widget. For example, in the code below, the color scheme from seed is set to deepPurple and divider color is grey.</p> <?code-excerpt "lib/theme.dart (theme)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> theme: </span><span style="color:#0468D7">ThemeData</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> colorScheme: </span><span style="color:#0468D7">ColorScheme</span><span style="color:#222222">.</span><span style="color:#6200EE">fromSeed</span><span style="color:#222222">(seedColor: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.deepPurple),</span></span> <span class="line"><span style="color:#222222"> dividerColor: </span><span style="color:#0468D7">Colors</span><span style="color:#222222">.grey,</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="using-custom-fonts">Using custom fonts</h3><a class="heading-link" href="#using-custom-fonts" aria-label="Link to 'Using custom fonts' section">#</a></div><p>In UIKit, you import any <code>ttf</code> font files into your project and create a reference in the <code>info.plist</code> file. In Flutter, place the font file in a folder and reference it in the <code>pubspec.yaml</code> file, similar to how you import images.</p><div class="code-block-wrapper language-yaml"><div class="code-block-body"><span class="code-block-language" title="Language yaml">yaml</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">fonts</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#222222"> - </span><span style="color:#0468D7">family</span><span style="color:#222222">: </span><span style="color:#0C7064">MyCustomFont</span></span> <span class="line"><span style="color:#0468D7"> fonts</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#222222"> - </span><span style="color:#0468D7">asset</span><span style="color:#222222">: </span><span style="color:#0C7064">fonts/MyCustomFont.ttf</span></span> <span class="line"><span style="color:#222222"> - </span><span style="color:#0468D7">style</span><span style="color:#222222">: </span><span style="color:#0C7064">italic</span></span></code></pre></div></div><p>Then assign the font to your <code>Text</code> widget:</p> <?code-excerpt "lib/text.dart (custom-font)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">@override</span></span> <span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#0C7064"> 'This is a custom font text'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> style: </span><span style="color:#0468D7">TextStyle</span><span style="color:#222222">(fontFamily: </span><span style="color:#0C7064">'MyCustomFont'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="styling-text">Styling text</h3><a class="heading-link" href="#styling-text" aria-label="Link to 'Styling text' section">#</a></div><p>Along with fonts, you can customize other styling elements on a <code>Text</code> widget. The style parameter of a <code>Text</code> widget takes a <code>TextStyle</code> object, where you can customize many parameters, such as:</p><ul><li><code>color</code></li><li><code>decoration</code></li><li><code>decorationColor</code></li><li><code>decorationStyle</code></li><li><code>fontFamily</code></li><li><code>fontSize</code></li><li><code>fontStyle</code></li><li><code>fontWeight</code></li><li><code>hashCode</code></li><li><code>height</code></li><li><code>inherit</code></li><li><code>letterSpacing</code></li><li><code>textBaseline</code></li><li><code>wordSpacing</code></li></ul><div class="header-wrapper"><h3 id="bundling-images-in-apps">Bundling images in apps</h3><a class="heading-link" href="#bundling-images-in-apps" aria-label="Link to 'Bundling images in apps' section">#</a></div><p>While iOS treats images and assets as distinct items, Flutter apps have only assets. Resources that are placed in the <code>Images.xcasset</code> folder on iOS, are placed in an assets' folder for Flutter. As with iOS, assets are any type of file, not just images. For example, you might have a JSON file located in the <code>my-assets</code> folder:</p><div class="code-block-wrapper language-plaintext"><div class="code-block-body"><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span>my-assets/data.json</span></span></code></pre></div></div><p>Declare the asset in the <code>pubspec.yaml</code> file:</p><div class="code-block-wrapper language-yaml"><div class="code-block-body"><span class="code-block-language" title="Language yaml">yaml</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">assets</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#222222"> - </span><span style="color:#0C7064">my-assets/data.json</span></span></code></pre></div></div><p>And then access it from code using an <a href="https://api.flutter.dev/flutter/services/AssetBundle-class.html"><code>AssetBundle</code></a>:</p> <?code-excerpt "lib/asset_bundle.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:async'</span><span style="color:#BD2314"> show</span><span style="color:#222222"> Future;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/services.dart'</span><span style="color:#BD2314"> show</span><span style="color:#222222"> rootBundle;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">> </span><span style="color:#6200EE">loadAsset</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> await</span><span style="color:#222222"> rootBundle.</span><span style="color:#6200EE">loadString</span><span style="color:#222222">(</span><span style="color:#0C7064">'my-assets/data.json'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>For images, Flutter follows a simple density-based format like iOS. Image assets might be <code>1.0x</code>, <code>2.0x</code>, <code>3.0x</code>, or any other multiplier. Flutter's <a href="https://api.flutter.dev/flutter/dart-ui/FlutterView/devicePixelRatio.html"><code>devicePixelRatio</code></a> expresses the ratio of physical pixels in a single logical pixel.</p><p>Assets are located in any arbitrary folder— Flutter has no predefined folder structure. You declare the assets (with location) in the <code>pubspec.yaml</code> file, and Flutter picks them up.</p><p>For example, to add an image called <code>my_icon.png</code> to your Flutter project, you might decide to store it in a folder arbitrarily called <code>images</code>. Place the base image (1.0x) in the <code>images</code> folder, and the other variants in sub-folders named after the appropriate ratio multiplier:</p><div class="code-block-wrapper language-plaintext"><div class="code-block-body"><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span>images/my_icon.png // Base: 1.0x image</span></span> <span class="line"><span>images/2.0x/my_icon.png // 2.0x image</span></span> <span class="line"><span>images/3.0x/my_icon.png // 3.0x image</span></span></code></pre></div></div><p>Next, declare these images in the <code>pubspec.yaml</code> file:</p><div class="code-block-wrapper language-yaml"><div class="code-block-body"><span class="code-block-language" title="Language yaml">yaml</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">assets</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#222222"> - </span><span style="color:#0C7064">images/my_icon.png</span></span></code></pre></div></div><p>You can now access your images using <code>AssetImage</code>:</p> <?code-excerpt "lib/images.dart (asset-image)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">image: </span><span style="color:#0468D7">AssetImage</span><span style="color:#222222">(</span><span style="color:#0C7064">'images/a_dot_burr.jpeg'</span><span style="color:#222222">),</span></span></code></pre></div></div><p>or directly in an <code>Image</code> widget:</p> <?code-excerpt "lib/images.dart (image-asset)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">@override</span></span> <span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Image</span><span style="color:#222222">.</span><span style="color:#6200EE">asset</span><span style="color:#222222">(</span><span style="color:#0C7064">'images/my_image.png'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>For more details, see <a href="/ui/assets/assets-and-images">Adding Assets and Images in Flutter</a>.</p><div class="header-wrapper"><h2 id="form-input">Form input</h2><a class="heading-link" href="#form-input" aria-label="Link to 'Form input' section">#</a></div><p>This section discusses how to use forms in Flutter and how they compare with UIKit.</p><div class="header-wrapper"><h3 id="retrieving-user-input">Retrieving user input</h3><a class="heading-link" href="#retrieving-user-input" aria-label="Link to 'Retrieving user input' section">#</a></div><p>Given how Flutter uses immutable widgets with a separate state, you might be wondering how user input fits into the picture. In UIKit, you usually query the widgets for their current values when it's time to submit the user input, or action on it. How does that work in Flutter?</p><p>In practice forms are handled, like everything in Flutter, by specialized widgets. If you have a <code>TextField</code> or a <code>TextFormField</code>, you can supply a <a href="https://api.flutter.dev/flutter/widgets/TextEditingController-class.html"><code>TextEditingController</code></a> to retrieve user input:</p> <?code-excerpt "lib/form.dart (my-form-state)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _MyFormState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">MyForm</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#6E6E70"> // Create a text controller and use it to retrieve the current value.</span></span> <span class="line"><span style="color:#6E6E70"> // of the TextField!</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> myController = </span><span style="color:#0468D7">TextEditingController</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> dispose</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6E6E70"> // Clean up the controller when disposing of the Widget.</span></span> <span class="line"><span style="color:#222222"> myController.</span><span style="color:#6200EE">dispose</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">dispose</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Retrieve Text Input'</span><span style="color:#222222">)),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">16</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">TextField</span><span style="color:#222222">(controller: myController),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> floatingActionButton: </span><span style="color:#0468D7">FloatingActionButton</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#6E6E70"> // When the user presses the button, show an alert dialog with the</span></span> <span class="line"><span style="color:#6E6E70"> // text the user has typed into our text field.</span></span> <span class="line"><span style="color:#222222"> onPressed: () {</span></span> <span class="line"><span style="color:#6200EE"> showDialog</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> context: context,</span></span> <span class="line"><span style="color:#222222"> builder: (context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> AlertDialog</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#6E6E70"> // Retrieve the text the user has typed in using our</span></span> <span class="line"><span style="color:#6E6E70"> // TextEditingController.</span></span> <span class="line"><span style="color:#222222"> content: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(myController.text),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> tooltip: </span><span style="color:#0C7064">'Show me the value!'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Icon</span><span style="color:#222222">(</span><span style="color:#0468D7">Icons</span><span style="color:#222222">.text_fields),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>You can find more information and the full code listing in <a href="/cookbook/forms/retrieve-input">Retrieve the value of a text field</a>, from the <a href="/cookbook">Flutter cookbook</a>.</p><div class="header-wrapper"><h3 id="placeholder-in-a-text-field">Placeholder in a text field</h3><a class="heading-link" href="#placeholder-in-a-text-field" aria-label="Link to 'Placeholder in a text field' section">#</a></div><p>In Flutter, you can easily show a "hint" or a placeholder text for your field by adding an <code>InputDecoration</code> object to the decoration constructor parameter for the <code>Text</code> widget:</p> <?code-excerpt "lib/form.dart (input-hint)" replace="/return const //g;/;//g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">TextField</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> decoration: </span><span style="color:#0468D7">InputDecoration</span><span style="color:#222222">(hintText: </span><span style="color:#0C7064">'This is a hint'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222">)</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="showing-validation-errors">Showing validation errors</h3><a class="heading-link" href="#showing-validation-errors" aria-label="Link to 'Showing validation errors' section">#</a></div><p>Just as you would with a "hint", pass an <code>InputDecoration</code> object to the decoration constructor for the <code>Text</code> widget.</p><p>However, you don't want to start off by showing an error. Instead, when the user has entered invalid data, update the state, and pass a new <code>InputDecoration</code> object.</p> <?code-excerpt "lib/validation_errors.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"><span style="color:#6E6E70"> // This widget is the root of your application.</span></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222">? _errorText;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#6200EE"> isEmail</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> em) {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222"> emailRegexp =</span></span> <span class="line"><span style="color:#0C7064"> r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|'</span></span> <span class="line"><span style="color:#0C7064"> r'(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|'</span></span> <span class="line"><span style="color:#0C7064"> r'(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> RegExp</span><span style="color:#222222"> regExp = </span><span style="color:#0468D7">RegExp</span><span style="color:#222222">(emailRegexp);</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#222222"> regExp.</span><span style="color:#6200EE">hasMatch</span><span style="color:#222222">(em);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">Center</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">TextField</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> onSubmitted: (text) {</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (!</span><span style="color:#6200EE">isEmail</span><span style="color:#222222">(text)) {</span></span> <span class="line"><span style="color:#222222"> _errorText = </span><span style="color:#0C7064">'Error: This is not an email'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#BD2314">else</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#222222"> _errorText = </span><span style="color:#0C7064">null</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> decoration: </span><span style="color:#0468D7">InputDecoration</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> hintText: </span><span style="color:#0C7064">'This is a hint'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> errorText: _errorText,</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="threading-asynchronicity">Threading & asynchronicity</h2><a class="heading-link" href="#threading-asynchronicity" aria-label="Link to 'Threading & asynchronicity' section">#</a></div><p>This section discusses concurrency in Flutter and how it compares with UIKit.</p><div class="header-wrapper"><h3 id="writing-asynchronous-code">Writing asynchronous code</h3><a class="heading-link" href="#writing-asynchronous-code" aria-label="Link to 'Writing asynchronous code' section">#</a></div><p>Dart has a single-threaded execution model, with support for <code>Isolate</code>s (a way to run Dart code on another thread), an event loop, and asynchronous programming. Unless you spawn an <code>Isolate</code>, your Dart code runs in the main UI thread and is driven by an event loop. Flutter's event loop is equivalent to the iOS main loop—that is, the <code>Looper</code> that is attached to the main thread.</p><p>Dart's single-threaded model doesn't mean you are required to run everything as a blocking operation that causes the UI to freeze. Instead, use the asynchronous facilities that the Dart language provides, such as <code>async</code>/<code>await</code>, to perform asynchronous work.</p><p>For example, you can run network code without causing the UI to hang by using <code>async</code>/<code>await</code> and letting Dart do the heavy lifting:</p> <?code-excerpt "lib/async.dart (load-data)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(</span><span style="color:#0C7064">'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = </span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Once the <code>await</code>ed network call is done, update the UI by calling <code>setState()</code>, which triggers a rebuild of the widget subtree and updates the data.</p><p>The following example loads data asynchronously and displays it in a <code>ListView</code>:</p> <?code-excerpt "lib/async.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:convert'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:http/http.dart'</span><span style="color:#BD2314"> as</span><span style="color:#222222"> http;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>> data = <</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>[];</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#6200EE"> loadData</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(</span><span style="color:#0C7064">'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = </span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> index) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Row </span><span style="color:#0C7064">${</span><span style="color:#222222">data</span><span style="color:#0C7064">[</span><span style="color:#222222">index</span><span style="color:#0C7064">][</span><span style="color:#0C7064">'title'</span><span style="color:#0C7064">]}</span><span style="color:#0C7064">'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#0468D7">ListView</span><span style="color:#222222">.</span><span style="color:#6200EE">builder</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> itemCount: data.length,</span></span> <span class="line"><span style="color:#222222"> itemBuilder: (context, index) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(index);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Refer to the next section for more information on doing work in the background, and how Flutter differs from iOS.</p><div class="header-wrapper"><h3 id="moving-to-the-background-thread">Moving to the background thread</h3><a class="heading-link" href="#moving-to-the-background-thread" aria-label="Link to 'Moving to the background thread' section">#</a></div><p>Since Flutter is single threaded and runs an event loop (like Node.js), you don't have to worry about thread management or spawning background threads. If you're doing I/O-bound work, such as disk access or a network call, then you can safely use <code>async</code>/<code>await</code> and you're done. If, on the other hand, you need to do computationally intensive work that keeps the CPU busy, you want to move it to an <code>Isolate</code> to avoid blocking the event loop.</p><p>For I/O-bound work, declare the function as an <code>async</code> function, and <code>await</code> on long-running tasks inside the function:</p> <?code-excerpt "lib/async.dart (load-data)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(</span><span style="color:#0C7064">'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = </span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This is how you typically do network or database calls, which are both I/O operations.</p><p>However, there are times when you might be processing a large amount of data and your UI hangs. In Flutter, use <code>Isolate</code>s to take advantage of multiple CPU cores to do long-running or computationally intensive tasks.</p><p>Isolates are separate execution threads that do not share any memory with the main execution memory heap. This means you can't access variables from the main thread, or update your UI by calling <code>setState()</code>. Isolates are true to their name, and cannot share memory (in the form of static fields, for example).</p><p>The following example shows, in a simple isolate, how to share data back to the main thread to update the UI.</p> <?code-excerpt "lib/isolates.dart (load-data)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ReceivePort</span><span style="color:#222222"> receivePort = </span><span style="color:#0468D7">ReceivePort</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#BD2314"> await</span><span style="color:#0468D7"> Isolate</span><span style="color:#222222">.</span><span style="color:#6200EE">spawn</span><span style="color:#222222">(dataLoader, receivePort.sendPort);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // The 'echo' isolate sends its SendPort as the first message.</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222"> sendPort = </span><span style="color:#BD2314">await</span><span style="color:#222222"> receivePort.first </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>> msg = </span><span style="color:#BD2314">await</span><span style="color:#6200EE"> sendReceive</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> sendPort,</span></span> <span class="line"><span style="color:#0C7064"> 'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = msg;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// The entry point for the isolate.</span></span> <span class="line"><span style="color:#BD2314">static</span><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">dataLoader</span><span style="color:#222222">(</span><span style="color:#0468D7">SendPort</span><span style="color:#222222"> sendPort) </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6E6E70"> // Open the ReceivePort for incoming messages.</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ReceivePort</span><span style="color:#222222"> port = </span><span style="color:#0468D7">ReceivePort</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // Notify any other isolates what port this isolate listens to.</span></span> <span class="line"><span style="color:#222222"> sendPort.</span><span style="color:#6200EE">send</span><span style="color:#222222">(port.sendPort);</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> await</span><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#BD2314">final</span><span style="color:#0468D7"> dynamic</span><span style="color:#222222"> msg </span><span style="color:#BD2314">in</span><span style="color:#222222"> port) {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> url = msg[</span><span style="color:#0C7064">0</span><span style="color:#222222">] </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> String</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222"> replyTo = msg[</span><span style="color:#0C7064">1</span><span style="color:#222222">] </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(url);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6E6E70"> // Lots of JSON to parse</span></span> <span class="line"><span style="color:#222222"> replyTo.</span><span style="color:#6200EE">send</span><span style="color:#222222">(</span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body) </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>> </span><span style="color:#6200EE">sendReceive</span><span style="color:#222222">(</span><span style="color:#0468D7">SendPort</span><span style="color:#222222"> port, </span><span style="color:#0468D7">String</span><span style="color:#222222"> msg) {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ReceivePort</span><span style="color:#222222"> response = </span><span style="color:#0468D7">ReceivePort</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> port.</span><span style="color:#6200EE">send</span><span style="color:#222222">(<</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[msg, response.sendPort]);</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#222222"> response.first </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>>;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here, <code>dataLoader()</code> is the <code>Isolate</code> that runs in its own separate execution thread. In the isolate, you can perform more CPU intensive processing (parsing a big JSON, for example), or perform computationally intensive math, such as encryption or signal processing.</p><p>You can run the full example below:</p> <?code-excerpt "lib/isolates.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:async'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:convert'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:isolate'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:http/http.dart'</span><span style="color:#BD2314"> as</span><span style="color:#222222"> http;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>> data = <</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>[];</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#6200EE"> loadData</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#BD2314"> get</span><span style="color:#222222"> showLoadingDialog => data.isEmpty;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ReceivePort</span><span style="color:#222222"> receivePort = </span><span style="color:#0468D7">ReceivePort</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#BD2314"> await</span><span style="color:#0468D7"> Isolate</span><span style="color:#222222">.</span><span style="color:#6200EE">spawn</span><span style="color:#222222">(dataLoader, receivePort.sendPort);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // The 'echo' isolate sends its SendPort as the first message.</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222"> sendPort = </span><span style="color:#BD2314">await</span><span style="color:#222222"> receivePort.first </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>> msg = </span><span style="color:#BD2314">await</span><span style="color:#6200EE"> sendReceive</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> sendPort,</span></span> <span class="line"><span style="color:#0C7064"> 'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = msg;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // The entry point for the isolate.</span></span> <span class="line"><span style="color:#BD2314"> static</span><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">dataLoader</span><span style="color:#222222">(</span><span style="color:#0468D7">SendPort</span><span style="color:#222222"> sendPort) </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6E6E70"> // Open the ReceivePort for incoming messages.</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ReceivePort</span><span style="color:#222222"> port = </span><span style="color:#0468D7">ReceivePort</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // Notify any other isolates what port this isolate listens to.</span></span> <span class="line"><span style="color:#222222"> sendPort.</span><span style="color:#6200EE">send</span><span style="color:#222222">(port.sendPort);</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> await</span><span style="color:#BD2314"> for</span><span style="color:#222222"> (</span><span style="color:#BD2314">final</span><span style="color:#0468D7"> dynamic</span><span style="color:#222222"> msg </span><span style="color:#BD2314">in</span><span style="color:#222222"> port) {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> url = msg[</span><span style="color:#0C7064">0</span><span style="color:#222222">] </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> String</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222"> replyTo = msg[</span><span style="color:#0C7064">1</span><span style="color:#222222">] </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> SendPort</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(url);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6E6E70"> // Lots of JSON to parse</span></span> <span class="line"><span style="color:#222222"> replyTo.</span><span style="color:#6200EE">send</span><span style="color:#222222">(</span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body) </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>> </span><span style="color:#6200EE">sendReceive</span><span style="color:#222222">(</span><span style="color:#0468D7">SendPort</span><span style="color:#222222"> port, </span><span style="color:#0468D7">String</span><span style="color:#222222"> msg) {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> ReceivePort</span><span style="color:#222222"> response = </span><span style="color:#0468D7">ReceivePort</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> port.</span><span style="color:#6200EE">send</span><span style="color:#222222">(<</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[msg, response.sendPort]);</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#222222"> response.first </span><span style="color:#BD2314">as</span><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>>;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getBody</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#222222"> showLoadingDialog = data.isEmpty;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (showLoadingDialog) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getProgressDialog</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#BD2314">else</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getListView</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getProgressDialog</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> Center</span><span style="color:#222222">(child: </span><span style="color:#0468D7">CircularProgressIndicator</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ListView</span><span style="color:#6200EE"> getListView</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> ListView</span><span style="color:#222222">.</span><span style="color:#6200EE">builder</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> itemCount: data.length,</span></span> <span class="line"><span style="color:#222222"> itemBuilder: (context, position) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(position);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> i) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">"Row </span><span style="color:#0C7064">${</span><span style="color:#222222">data</span><span style="color:#0C7064">[</span><span style="color:#222222">i</span><span style="color:#0C7064">][</span><span style="color:#0C7064">"title"</span><span style="color:#0C7064">]}</span><span style="color:#0C7064">"</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#6200EE">getBody</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="making-network-requests">Making network requests</h3><a class="heading-link" href="#making-network-requests" aria-label="Link to 'Making network requests' section">#</a></div><p>Making a network call in Flutter is easy when you use the popular <a href="https://pub.dev/packages/http"><code>http</code> package</a>. This abstracts away a lot of the networking that you might normally implement yourself, making it simple to make network calls.</p><p>To add the <code>http</code> package as a dependency, run <code>flutter pub add</code>:</p><div class="code-block-wrapper language-console"><div class="code-block-body"><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">flutter pub add http</span></span></code></pre></div></div><p>To make a network call, call <code>await</code> on the <code>async</code> function <code>http.get()</code>:</p> <?code-excerpt "lib/progress.dart (load-data)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(</span><span style="color:#0C7064">'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = </span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="showing-the-progress-on-long-running-tasks">Showing the progress on long-running tasks</h3><a class="heading-link" href="#showing-the-progress-on-long-running-tasks" aria-label="Link to 'Showing the progress on long-running tasks' section">#</a></div><p>In UIKit, you typically use a <code>UIProgressView</code> while executing a long-running task in the background.</p><p>In Flutter, use a <code>ProgressIndicator</code> widget. Show the progress programmatically by controlling when it's rendered through a boolean flag. Tell Flutter to update its state before your long-running task starts, and hide it after it ends.</p><p>In the example below, the build function is separated into three different functions. If <code>showLoadingDialog</code> is <code>true</code> (when <code>widgets.length == 0</code>), then render the <code>ProgressIndicator</code>. Otherwise, render the <code>ListView</code> with the data returned from a network call.</p> <?code-excerpt "lib/progress.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'dart:convert'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:flutter/material.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#BD2314">import</span><span style="color:#0C7064"> 'package:http/http.dart'</span><span style="color:#BD2314"> as</span><span style="color:#222222"> http;</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> runApp</span><span style="color:#222222">(</span><span style="color:#BD2314">const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleApp</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatelessWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleApp</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> MaterialApp</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> home: </span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> StatefulWidget</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> const</span><span style="color:#0468D7"> SampleAppPage</span><span style="color:#222222">({</span><span style="color:#BD2314">super</span><span style="color:#222222">.key});</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> </span><span style="color:#6200EE">createState</span><span style="color:#222222">() => </span><span style="color:#0468D7">_SampleAppPageState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314">class</span><span style="color:#0468D7"> _SampleAppPageState</span><span style="color:#BD2314"> extends</span><span style="color:#0468D7"> State</span><span style="color:#222222"><</span><span style="color:#0468D7">SampleAppPage</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222"><</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>> data = <</span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>>[];</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#BD2314"> void</span><span style="color:#6200EE"> initState</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> super</span><span style="color:#222222">.</span><span style="color:#6200EE">initState</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#6200EE"> loadData</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#BD2314"> get</span><span style="color:#222222"> showLoadingDialog => data.isEmpty;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Future</span><span style="color:#222222"><</span><span style="color:#BD2314">void</span><span style="color:#222222">> </span><span style="color:#6200EE">loadData</span><span style="color:#222222">() </span><span style="color:#BD2314">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#0468D7"> Uri</span><span style="color:#222222"> dataURL = </span><span style="color:#0468D7">Uri</span><span style="color:#222222">.</span><span style="color:#6200EE">parse</span><span style="color:#222222">(</span><span style="color:#0C7064">'https://jsonplaceholder.typicode.com/posts'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#BD2314"> final</span><span style="color:#222222"> http.</span><span style="color:#0468D7">Response</span><span style="color:#222222"> response = </span><span style="color:#BD2314">await</span><span style="color:#222222"> http.</span><span style="color:#6200EE">get</span><span style="color:#222222">(dataURL);</span></span> <span class="line"><span style="color:#6200EE"> setState</span><span style="color:#222222">(() {</span></span> <span class="line"><span style="color:#222222"> data = </span><span style="color:#6200EE">jsonDecode</span><span style="color:#222222">(response.body);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getBody</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> if</span><span style="color:#222222"> (showLoadingDialog) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getProgressDialog</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getListView</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getProgressDialog</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#BD2314"> const</span><span style="color:#0468D7"> Center</span><span style="color:#222222">(child: </span><span style="color:#0468D7">CircularProgressIndicator</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ListView</span><span style="color:#6200EE"> getListView</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> ListView</span><span style="color:#222222">.</span><span style="color:#6200EE">builder</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> itemCount: data.length,</span></span> <span class="line"><span style="color:#222222"> itemBuilder: (context, index) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(index);</span></span> <span class="line"><span style="color:#222222"> },</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> getRow</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> i) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Padding</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> padding: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> EdgeInsets</span><span style="color:#222222">.</span><span style="color:#6200EE">all</span><span style="color:#222222">(</span><span style="color:#0C7064">10</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#0C7064">"Row </span><span style="color:#0C7064">${</span><span style="color:#222222">data</span><span style="color:#0C7064">[</span><span style="color:#222222">i</span><span style="color:#0C7064">][</span><span style="color:#0C7064">"title"</span><span style="color:#0C7064">]}</span><span style="color:#0C7064">"</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#BD2314"> @override</span></span> <span class="line"><span style="color:#0468D7"> Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#BD2314"> return</span><span style="color:#0468D7"> Scaffold</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> appBar: </span><span style="color:#0468D7">AppBar</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> title: </span><span style="color:#BD2314">const</span><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#0C7064">'Sample App'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ),</span></span> <span class="line"><span style="color:#222222"> body: </span><span style="color:#6200EE">getBody</span><span style="color:#222222">(),</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p id="page-github-links"><span>Unless stated otherwise, the documentation on this site reflects the latest stable version of Flutter. Page last updated on 2024-09-09.</span> <a href="https://github.com/flutter/website/tree/main/src/content/get-started/flutter-for/uikit-devs.md" target="_blank" rel="noopener">View source</a> <span>or </span><a href="https://github.com/flutter/website/issues/new?template=1_page_issue.yml&&page-url=https://docs.flutter.dev/get-started/flutter-for/uikit-devs/&page-source=https://github.com/flutter/website/tree/main/src/content/get-started/flutter-for/uikit-devs.md" title="Report an issue with this page" target="_blank" rel="noopener">report an issue</a>.</p></div></main></div></div><footer class="site-footer"><div class="container-fluid"><div class="row"><div class="col-md-12 site-footer__wrapper"><div class="site-footer__logo"><img src="/assets/images/branding/flutter/logo/flutter-mono-81x100.png" alt="Flutter Logo" width="81" height="100"></div><div class="site-footer__content"><ul class="site-footer__link-list"><li><a href="/tos">terms</a></li><li><a href="/brand">brand usage</a></li><li><a href="/security">security</a></li><li><a href="https://www.google.com/intl/en/policies/privacy">privacy</a></li><li><a href="https://esflutter.dev/">español</a></li><li><a href="https://flutter.cn" class="text-nowrap">社区中文资源</a></li><li><a href="https://blog.google/inside-google/company-announcements/standing-with-black-community">We stand in solidarity with the Black community. Black Lives Matter.</a></li></ul><p class="licenses">Except as otherwise noted, this work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0">Creative Commons Attribution 4.0 International License</a>, and code samples are licensed under the BSD License.</p></div></div></div></div></footer><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js" integrity="sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/js/bootstrap.min.js" integrity="sha512-7rusk8kGPFynZWu26OKbTeI+QPoYchtxsmPeBqkHIEXJxeun4yJ4ISYe7C6sz9wdxeE1Gk3VxsIWgCZTc+vX3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script><script src="/assets/js/tabs.js"></script><script src="/assets/js/archive.js"></script><script src="/assets/js/main.js"></script></body></html>