{"componentChunkName":"component---src-templates-lesson-post-js","path":"/lesson/intro-to-widgets","result":{"data":{"strapiLesson":{"id":"Lesson_63","author":{"email":"eric@ericwindmill.com","username":"Eric Windmill","twitter":"ericwindmill"},"content":"*Widgets* are building blocks which you, the developer, will compose together to make a UI. When learning Flutter, you'll hear the phrase \"everything is a widget\" quite often. For our purposes now, that's true. Every object in your Flutter application's UI is a widget. Structure is defined with widgets, styles are defined with widgets, even animations and routing is handled by widgets. And, widgets are just Dart classes that know how to describe their view.\n\nIn the image below, a few of the widgets on-screen are highlighted.\n\n<img src=\"counter_app_annotated.png\" alt=\"drawing\" style=\"width:400px;\"/>\n\nThese are some of the most basic widgets, but there are a lot of implications here. First, you have a `Text` widget and a `Button` widget. These represent tangible pieces of UI. But, notice that there's also a `Column` widget. This widget tells other widgets to arrange themselves vertically. Importantly, there's no CSS or styling language, it's just widgets.\n\n\n### Built in Widgets\n\nThe above image shows the \"counter app\", which is the default application that's built when you start a new Flutter project. Which means that everything on that screen is built into Flutter. \n\nFlutter offers several widgets out of the box, which we, the Flutter developers, will combine to make custom widgets and robust UI. Here are just a few of the most basic built in widgets in Flutter, separated by their use.\n\n* _Layout_--`Row`, `Column`, `Scaffold`, `Stack`\n* _Structures_--`Button`, `Toast`, `MenuDrawer`\n* _Styles_--`TextStyle`, `Color`\n* _Animations_--`FadeInPhoto`, transformations\n* _Positioning and alignment_--`Center`, `Padding`\n\n### Writing a widget in code\n\nMost of the Flutter code you write will be creating custom widgets. Widgets are just Dart class that _extend_ a `Widget` class. Suppose you wanted to make a button widget with custom styling. This is how you'd define the class:\n\n```dart\nclass AlertButton extends StatelessWidget {\n  // class members\n}\n```\n\n<div class=\"aside\">\nThe class `StatelessWidget` is the most basic widget class, and the one you'll use the most often. We'll cover the different types of widgets later.\n</div>\n\n\nWhen creating widgets, there is one requirement enforced by the widget superclass. It must have a `build` method. This method must return other widgets. It's the method that you use to compose widgets together to make a UI.\n\nUsing that same `AlertButton` example:\n\n```dart\nclass AlertButton extends StatelessWidget {\n\n  @override\n  Widget build(BuildContext context) {\n    return RaisedButton(\n      color: Colors.red,\n      child: Text(\"Alert!\")\n    );\n  } \n}\n``` \n\nOther than the `build` method, Widgets are just like any other Dart class. You can add methods and properties to the widget classes.\n\n```dart\nclass AlertButton extends StatelessWidget {\n  // a property on this class\n  final String text;\n\n  // a constructor for this class\n  AlertButton(this.text);\n\n  @override\n  Widget build(BuildContext context) {\n    return RaisedButton(\n      color: Colors.red,\n      child: Text(text), // use the text passed in to the constructor.\n    );\n  } \n}\n``` \n\n\n","updated_at":"Friday, 24th of July, 2020","slug":"intro-to-widgets","strapiId":63,"title":"Intro to Widgets","tutorial":{"category":"Flutter","title":"Widgets"}},"strapiTutorial":{"lessons":[{"author":1,"content":"Every Flutter widget has an `@override build()` method with the argument of `BuildContext`.\n\n```dart\nclass CartItemWidget extends StatelessWidget {\n\n  @override\n  Widget build(BuildContext context) {\n  // ...\n```\n\n<div class='aside'>\n\n### why BuildContext()\n\nSimply explain is that the `BuildContext` is:\n- the location of the `Widget` in the widget tree.\n- a widget of widgets, like nested.wrap `<div <div> .html>`\n- parent objects in qt and alike\n- In Flutter, everything is a Widget, down to the final `build.call()`\n- Until finally a widget is returned with its \"stuff,\" row dimentions et all\n\n</div>\n\nImportant concept to understand is that \n\n1 - Every `Widget` has its own `build()` and its `context`.\n2 - The BuildContext is the parent of the widget returned by the `build()` method._\n\n\nIn other words, the `buildContext` of the Widget that _calls_ `build()` is not the\nsame as the build context of the widget _returned_ by `build()`.\n\n```dart\nclass _MyHomePageState extends State<MyHomePage> {\n  _MyHomePageState() {\n    print(context.hashCode);\n    // prints 2011\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text(widget.title),\n      ),\n      body: new Container(),\n      floatingActionButton:\n          new FloatingActionButton(onPressed: () => print(context.hashCode)),\n          // prints 63\n    );\n  }\n}\n```\n\nIf you did this exact experiment, the print statements would be different, but\nthose are the actual numbers that I got.\n\n**But what does this actually mean?**\n\nThis is the one big **gotcha;-)**:  \n- It is easy to reference the _wrong_ `build()`\n- and its `context` \n- This can cause unexpected situations, specifically when using the `of()` method.\n\n### The 'of()' Method\n\nIn Flutter, as everthing are widgets, looking up and down the widget tree, in some cases, to\nreference other Widgets. This is required for some functionality.\n\nIn particular, widgets that want to use the State of `inherited` widgets need\nto be able to reference those inherited widgets. This usually comes in the form\nof the `of` method.\n\nFor example:\n\n```dart\n@override\nWidget build(context) {\n  return new Text('Hello, World',\n    style: new TextStyle(color: Theme.of(context).primaryColor),\n  );\n}\n```\n\nUnder the hood, that `of` method is looking up the tree for the next parent\nwidget that is of type `Theme`, and grabbing that primary color property. The\nframework can find the correct `Theme` object because it knows the tree in\nrelation to this `build context`.\n\n#### The Gotcha\n\nWith the scaffold, Flutter does give us a nice way to solve following problem...\n\nWhen creating some widgets, such as a snackbar, you have to grab the nearest\nScaffold context so that Flutter knows how to paint the snackbar, since\nScaffold is the widget that actually gives us access to displaying snackbars.\n\nConsider this:\n\n(hint: it doesn't work)\n\n```dart\n  @override\n  Widget build(BuildContext context) {\n    return new Scaffold(\n        appBar: new AppBar(\n          title: new Text(widget.title),\n        ),\n        body: new Container(),\n        /// Scaffold doesn't exist in this context here\n        /// because the context thats passed into 'build'\n        /// refers to the Widget 'above' this one in the tree,\n        /// and the Scaffold doesn't exist above this exact build method\n        ///\n        /// This will throw an error:\n        /// 'Scaffold.of() called with a context that does not contain a Scaffold.'\n        floatingActionButton: new FloatingActionButton(onPressed: () {\n          Scaffold.of(context).showSnackBar(\n                new SnackBar(\n                  content: new Text('SnackBar'),\n                ),\n              );\n        }));\n  }\n```\n\n### Builder Methods\n\n`Builder` is a widget that takes a closure and uses it to build its child\nwidgets. In laymans, you can use it to pass the context from a `build` method\ndirectly to children being returned in that `build` method.\n\nUsing the example above:\n\n```dart\n  @override\n  Widget build(BuildContext context) {\n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text(widget.title),\n      ),\n      body: new Container(),\n      /// Builders let you pass context\n      /// from your *current* build method\n      /// Directly to children returned in this build method\n      ///\n      /// The 'builder' property accepts a callback\n      /// which can be treated exactly as a 'build' method on any\n      /// widget\n      floatingActionButton: new Builder(builder: (context) {\n        return new FloatingActionButton(onPressed: () {\n          Scaffold.of(context).showSnackBar(\n                new SnackBar(\n                  backgroundColor: Colors.blue,\n                  content: new Text('SnackBar'),\n                ),\n              );\n        });\n      }),\n    );\n  }\n```\n\n<div class='aside'>\n\nYou could also solve this by simply making your build methods\nsmaller, and returning a Scaffold in a 'higher' widget. When in doubt, stick\nwith smaller return methods.\n\n</div>","created_at":"2020-07-21T16:15:19.204Z","id":67,"slug":"build-context","title":"BuildContext","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},{"author":1,"content":"At any given moment, your Flutter app will consist of many widgets, which are related via a tree structure. This isn't unlike the DOM in the web-browser, which organizes HTML elements in a tree of sorts. Not only is the widget tree an actual data structure built by the framework, its also a useful way to talk about your Flutter app.  \n\nThe following diagram shows what the widget tree for the counter app might look like. (Note that the counter app is the starter app that's generated when you run `flutter create` in your terminal.) \n\n<!-- TODO: insert image-->\n\nIn general, you build the widget tree via the `build` method in widget objects. Every time a build method returns more widgets, those widgets all become nodes in the tree. When a user is interacting with your application, Flutter uses this tree structure to represent your app's widgets. When a user navigates to a new screen, Flutter will remove all the widgets in the tree that are no longer used (from the screen they navigated away from) and replace them with widgets that represent the new page. \n\n","created_at":"2020-07-21T16:14:40.226Z","id":66,"slug":"the-widget-tree","title":"The Widget tree","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},{"author":1,"content":"In Flutter, _everything_ is a widget. Widgets are just tiny chunks of\nUI that you can combine to make a complete app. Building an app Flutter is\nlike building a lego set -- piece by piece.\n\nWidgets are nested inside of each other to build your app. Even the root of your\napp is just a widget. It's widgets all the way down.\n\nFlutter is unique in that _every_ aspect of UI is handled with Widgets.\n\nA widget might display something, it might help define design, it might help\nwith layout, or it may handle interaction. I really can't drive this home enough:\n_everything is a widget_.\n\n* A simple widget that displays text: `const Text('Hello World')`.\n* A simple widget that a user interacts with `const Button(onTap: ...callback...)`\n* A simple widget that adds a background color: `const BoxDecoration(background: Colors.blue)`\n\nIf you're coming from the web: imagine that your CSS, HTML, and JavaScript are all handled by\nwidgets. There is no markup language. There is no CSS. Just widgets.\n\n### Widget Hierarchy\n\nIn this picture, every thing that's outlined is a widget:\n\n![Outlined widgets](https://res.cloudinary.com/ericwindmill/image/upload/v1527539536/flutter_by_example/thinking_in_widgets.png)\n\nThis picture is from one of the tutorial apps on FlutterByExample, and this is\na detail page, of which there is one for every dog in the app.\n\nThe green outline represents the page. And a page in Flutter is a\nwidget. The blue outlines represent pieces of UI that logically group together.\nThe rest are outlined white, and they're simply dumb components that have no\nconcern over their content, they just display what they're told.\n\nThis is the widget hierarchy for this page:\n\n* PageWidget\n  * DogProfileWidget\n    * CircleImage\n    * Text\n    * Text\n    * Text\n    * Container\n      * Icon\n      * Text\n  * RateDogWidget\n    * Slider\n    * Text\n    * SubmitButton\n\n<div class=\"aside\">\nThis isn't _exactly_ accurate, there are layout widgets\nsuch as `columns`and `padding` in here that I'm glossing over.\n</div>\n\n### Design for Re-usability\n\nThe most important part of using Flutter Widgets effectively is designing your\nlowest level widgets to be reusable.\n\nFor example, the CircleImage widget from the image above:\n\n```dart\nclass CircleImage extends StatelessWidget {\n final String renderUrl;\n\n CircleImage(this.renderUrl);\n\n @override\n Widget build(BuildContext context) {\n   return new Container(\n    width: 100.0,\n    height: 100.0,\n    decoration: new BoxDecoration(\n      shape: BoxShape.circle,\n      image: new DecorationImage(\n        fit: BoxFit.cover,\n        image: new NetworkImage(renderUrl ?? ''),\n      ),\n    ),\n  );\n }\n}\n```\n\nThen, anywhere in your app, you can reuse this Widget: `new CircleImage('https..)`.\nThis component is designed for re-usability because anywhere in your app that\nyou may want a round image of a certain size, you can just pass in a url and\nthere you have it. There's no need to re-write this widget over and over.\n\nAnd, this circle image doesn't care at all about what it's displaying. It's\njust enforcing styles.\n\nIn the test app that these images are from, I also have a list of all the dogs\nin the app. Heres a picture of one of the cards:\n\n![Dog card](https://res.cloudinary.com/ericwindmill/image/upload/v1527539533/flutter_by_example/Screen_Shot_2018-05-27_at_12.13.40_PM.png)\n\nIn that Widget, I don't need to rewrite the circle image, because I've already\nbuilt it once.","created_at":"2020-07-21T16:16:34.917Z","id":69,"slug":"thinking-in-widgets","title":"Thinking in widgets","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},{"author":1,"content":"When a Flutter builds a \n[`StatefulWidget`](https://docs.flutter.io/flutter/widgets/StatefulWidget-class.html), it \ncreates a [`State`](https://docs.flutter.io/flutter/widgets/State-class.html) object. This\nobject is where all the \n**[mutable](https://en.wikipedia.org/wiki/Immutable_object)** state for that widget is held.\n\nThe concept of state is defined by two things:\n\n1. The data used by the widget might change.\n2. The data _can't_ be read synchronously when the widget is built. (All state\n   must be established by the time the `build` method is called).\n   \n<div class='post-toc'>\n\nThe lifecycle has the following simplified steps:\n\n* [createState()](#1-createstate)\n* [mounted == true](#2-mounted-is-true)\n* [initState()](#3-initstate)\n* [didChangeDependencies()](#4-didChangeDependencies)\n* [build()](#5-build)\n* [didUpdateWidget()](#6-didupdatewidget)\n* [setState()](#7-setstate)\n* [deactivate()](#8-deactivate)\n* [dispose()](#9-dispose)\n* [mounted == false](#10-mounted-is-false)\n\n</div>\n\n\n\n### Why Are StatefulWidget and State Separate Classes?\n\nIn one word: performance.\n\nThe tldr version is that `State` objects are long lived, but `StatefulWidget`s\n(and all `Widget` subclasses) are thrown away and rebuilt whenever configuration\nchanges. It's very inexpensive ie cheap for Flutter to rebuild a mutable widget.\n\nAs `State` isn't blown away on every rebuild, it avoids \nexpensive computations, and gets at the `state`s property, getters, setters etc everytime\nsomething is rebuilt frame by frame.\n\nImportant is that this is what allows Flutter animations to exist. As `State` isn't\nthrown away, it can constantly be rebuilding it's `Widget` in response to data\nchanges, and when required, if any.\n\n### 1. createState()\n\nWhen Flutter is instructed to build a \n[`StatefulWidget`](https://docs.flutter.io/flutter/widgets/StatefulWidget-class.html), it \nimmediately calls \n[`createState()`](https://docs.flutter.io/flutter/widgets/StatefulWidget/createState.html). This \nmethod _must_ exist. A StatefulWidget rarely needs to be more complicated than this.\n\n```dart\nclass MyHomePage extends StatefulWidget {\n  @override\n  _MyHomePageState createState() => new _MyHomePageState();\n}\n```\n\n### 2. mounted is true\n\nWhen [`createState`](https://docs.flutter.io/flutter/widgets/StatefulWidget/createState.html) \ncreates the state class, a `buildContext` is assigned to\nthat state. \n\nA [`BuildContext`](https://docs.flutter.io/flutter/widgets/BuildContext-class.html) is, overly \nsimplified, the place in the widget tree in which\nthis widget is placed. ![Here's a longer explanation.][https://flutterbyexample.com/build-context-class]\n\nAll widgets have a `bool this.mounted` property. It is turns `true` when the\n`buildContext` is assigned. It is an error to call `setState` when a widget is\nunmounted.\n\n<div class='tip'>\n\n**tip:** This property is useful when a method on your state calls `setState()`\nbut it isn't clear when or how often that method will be called. Perhaps its\nbeing called in response to a stream updating. You can use `if (mounted) {...`\nto make sure the State exists before calling `setState()`.\n\n</div>\n\n### 3. initState()\n\nThis is the first method called when the widget is created (after the class\nconstructor, of course.)\n\n[`initState`](https://docs.flutter.io/flutter/widgets/State/initState.html) is \ncalled **once and only once**. It must also call `super.initState()`.\n\nThis `@override` method is the best time to:\n\n1. Initialize data that relies on the specific BuildContext for the created\n   instance of the widget.\n2. Initialize properties that rely on this widgets 'parent' in the tree.\n3. Subscribe to Streams, ChangeNotifiers, or any other object that could change\n   the data on this widget.\n\n```dart\n@override\ninitState() {\n  super.initState();\n  // Add listeners to this class\n  cartItemStream.listen((data) {\n    _updateWidget(data);\n  });\n}\n```\n\n### 4. didChangeDependencies()\n\nThe [didChangeDependencies](https://docs.flutter.io/flutter/widgets/State/didChangeDependencies.html)\nmethod is called immediately after `initState` on the first time the\nwidget is built.\n\nIt will also be called whenever an object that this widget _depends on data\nfrom_ is called. For example, if it relies on an InheritedWidget, which updates.\n\n`build` is **always** called after `didChangeDependencies` is called, so this\nis rarely needed. However, this method is the first change you have to call\n`BuildContext.inheritFromWidgetOfExactType`. This essentially would make this\nState 'listen' to changes on a Widget it's inheriting data from.\n\nThe docs also suggest that it could be useful if you need to do network calls\n(or any other expensive action) when an InheritedWidget updates.\n\n### 5. build()\n\nThis method is called often (think fps + `render`). It is a required, `@override` and \nmust return a [`Widget`](https://docs.flutter.io/flutter/widgets/Widget-class.html).\n\nRemember that in Flutter all gui is a widget with a child or children, even \n['Padding'](https://docs.flutter.io/flutter/widgets/Padding-class.html), \n['Center'](https://docs.flutter.io/flutter/widgets/Center-class.html).\n\n### 6. didUpdateWidget(Widget oldWidget)\n\n[`didUpdateWidget()`](https://docs.flutter.io/flutter/widgets/State/didUpdateWidget.html) is called \nif the parent widget changes and has to rebuild this widget (because it needs\nto give it different data), but it's being rebuilt with the same `runtimeType`,\nthen this method is called.\n\nThis is because Flutter is re-using the `state`, which is long lived. In this\ncase, required is to initialize some data again, as one would in `initState()`.\n\nIf the state's `build()` method relies on a Stream or other object that can\nchange, unsubscribe from the old object and re-subscribe to the new instance in\n`didUpdateWidget()`.\n\n<div class='tip'>\n\n**tip**: This method is basically the replacement for 'initState()' if it is expected\nthe `Widget` associated with the widgets's `state` nrrds to to be rebuilt!\n\n</div>\n\nFlutter always called `build()` after this, so any subsequent further calls to `setState` is\nredundant.\n\n```dart\n@override\nvoid didUpdateWidget(Widget oldWidget) {\n  if (oldWidget.importantProperty != widget.importantProperty) {\n    _init();\n  }\n}\n```\n\n### 7. setState()\n\nThe ['setState()'](https://docs.flutter.io/flutter/widgets/State/setState.html) \nmethod is called often from the Flutter framework itself and from the developer.\n\nIt is used to notify the framework that \"data has changed\", and the widget at this\n`build context` should be rebuilt.\n\n`setState()` takes a callback which **cannot be async**. It is for this reason\nit can be called often as required, because repainting is cheap :-)\n\n```dart\nvoid updateProfile(String name) {\n setState(() => this.name = name);\n}\n```\n\n### 8. deactivate()\n\nThis is rarely used.\n\n['deactivate()'](https://docs.flutter.io/flutter/widgets/State/deactivate.html) is \ncalled when `State` is removed from the tree, _but it might be\nreinserted_ before the current frame change is finished. This method exists\nbasically because `State` objects can be moved from one point in a tree to\nanother.\n\n\n\n### 9. dispose()\n\n['dispose()'](https://docs.flutter.io/flutter/widgets/State/dispose.html) is called \nwhen the `State` object is removed, which is permanent.\n\nThis method is where to unsubscribe and cancel all animations, streams,\netc.\n\n### 10. mounted is false\n\nThe `state` object can never remount, and an error is thrown is `setState()` is\ncalled.\n","created_at":"2020-07-21T16:13:59.193Z","id":65,"slug":"stateful-widget-lifecycle","title":"StatefulWidget lifecycle","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},{"author":1,"content":"Flutter widgets must extend a handful of classes from the Flutter library. The two you'll use most are `StatelessWidget` and `StatefulWidget`.\n\nThe difference is that one has a concept of `State` within the Widget, which can be used to tell Flutter when to render and re-render. The other one is \"dumb\".\n\n### StatelessWidget\n\nA `StatelessWidget` is a widget that you (as the developer) are okay with being destroyed. In other words, no information is kept within it that, if lost, will matter. All of the widget's state or configuration is passed into it. Its only job is to display information and UI. Its life depends on outside forces. It doesn't tell the framework when to remove it from the tree, or when to rebuild it. Rather, the framework tells _it_ when to rebuild. \n\nWriting a `StatelessWidget` requires extending the correct class and including a `build` method.\n\n```dart\nclass TitleText extends StatelessWidget {\n  final String text;\n  \n  TitleText(this.text);\n\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: Text(text)\n    );\n  }\n}\n```\n\n### StatefulWidget\n\nA `Stateful Widget` is a bit different. It's actually two classes: a `State` object and the widget itself. The purpose of this class is to persist *state* when Flutter rebuilds widgets.\n\n\nIn Flutter, the concept of state is defined by two things:\n\n1. The data used by the widget might change.\n2. The data _can't_ be read synchronously when the widget is built. (All state\n   must be established by the time the `build` method is called). \n\nThe State object is special in that it has several methods that interact with Flutter in different ways. The most important of which is `setState`. \n\n`setState` is used to tell Flutter that it needs to _rebuild_, usually because something has changed and the screen needs to reflect that. In actuality, after `setState` is called, Flutter knows that it needs to call the `build` method again.\n\nIn this example, you can see setState called in the `_MyHomePageState.increaseCount` method. That will increase the `counter`  variable, and that value will be displayed  when `build` is called again (which is done automatically).\n\n```dart\nclass Counter extends StatefulWidget {\n  Counter({Key key, this.title}) : super(key: key);\n\n   // Stateful Widgets don't have build methods.\n   // They have createState() methods.\n   // Create State returns a class that extends Flutters State class.\n  @override\n  _MyHomePageState createState() => new _MyHomePageState();\n\n  // Stateful Widgets are rarely more complicated than this.\n}\n\nclass _MyHomePageState extends State<MyHomePage> {\n  int counter = 0;\n\n  void increaseCount() {\n\t// setState is a special method that tells Flutter to repaint\n\t// the view because state has been updated!\n\tsetState(() {\n      this.counter++;\n \t}\n  }\n\n\t// gotta have that build method!\n  Widget build(context) {\n\treturn new RaisedButton(\n      onPressed: increaseCount,\n\t  child: new Text('Tap to Increase'),\n\t);\n  }\n}\n```\n\nImportantly:\n\n- The `StatefulWidget` class must implement the `createState` method.\n- The `State` object must implement the `build` method.\n- The `StatefulWidget` is immutable.\n- The `State` object is mutable. ","created_at":"2020-07-21T16:12:58.163Z","id":64,"slug":"widget-types-stateful-and-stateless","title":"Widget types: Stateful and Stateless","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},{"author":1,"content":"If you've used Flutter before, you've probably come across the 'of' method on different classes here and there:\n\n```dart\nTheme.of(context).textTheme\nMediaQuery.of(context).size\n```\n\nThose widgets (Theme, MediaQuery) are Inherited widgets. Pretty much anywhere in your app, you can access your theme,\n because they're inherited.\n \nIn Flutter, every part of the sdk is exposed to the developer, so you can take advantage of the inherited widget \nyourself. You can use a custom InheritedWidget as a built-in central state storage, similar to a Redux Store or Vue's \nVuex Store.\n\nAfter you've set up a store like this, you'll be able to do something like this: \n\n```dart\nclass RedText extends StatelessWidget {\n  // ...\n  Widget build(BuildContext context) {\n    var state = StateContainer.of(context).state;\n    return new Text(\n      state.user.username,\n      style: const TextStyle(color: Colors.red),\n    );\n  // ...\n```\n\n### Lifting State Up\n\nWhen using an InheritedWidget as your state management tool, you're likely relying on an architecture pattern called \n'Lifting State Up'. \n\nConsider the starter Flutter app when you start a new project (the counter app). If you wanted to\n separate that app into two pages, one that displayed the counter, and one that allowed you to change the number. \n Suddenly, this incredibly simple app is confusing. Each time you change routes, you have to be passing this piece of\n  state (the counter) back and forth.\n  \nThe InheritedWidget solves this problem by giving an entire widget tree access to the same pieces of state. \n\n <img src=\"http://res.cloudinary.com/ericwindmill/image/upload/v1518974500/flutter_by_example/medium_tree.png\" />\n\nFor a super awesome detailed explanation of different Flutter architecture concepts, [watch Brain Egan's talk from \nDartConf 2018](https://www.youtube.com/watch?v=zKXz3pUkw9A&t=1467s). Just don't watch too much, or you'll be \nconvinced to use [flutter_redux](https://pub.dartlang.org/packages/flutter_redux), and you won't care about this article anymore. 🙃\n\nThe advantage to lifting state up rather than reaching for something like Redux, is that using an Inherited Widget is\n pretty simple to set up and use. \n \n**NB:** To be sure, I am a fan of Redux and Vuex and all the 'ux' things. This is just another tool in your toolbox \nfor when Redux is more than you need. \n\n### Why Bother?\n\nAt this point, you might be asking why you should bother with an InheritedWidget. Why not just stick with a stateful \nwidget at the apps root? \n\nWell really, that's what you are doing here. The inherited widget works in conjunction with a stateful widget and \nallows you to pass that StatefulWidgets state to *all* of its ancestors. Its a convenience widget. So you don't have \nto type the code in every class to pass state down to its children.\n\n##Pt: 1 Set up a boiler plate app\n\nFor this example, let's just make this simple app:\n\n<img src=\"http://res.cloudinary.com/ericwindmill/image/upload/v1523742041/blog_posts/inherited_test.gif\" />\n\nBasically this app's state is lifted up above the root Widget, and when you submit the form, it calls `setState` on \nthat inherited widgets state, which tells the main page that there's new information to render.\n\n### 1. The Material App Root\n\nThis is just your standard Flutter app set up:\n\n```dart\nvoid main() {\n  runApp(new UserApp());\n}\n\nclass UserApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return new MaterialApp(\n      home: new HomeScreen(),\n    );\n  }\n}\n```\n\n### 2. HomeScreen Widget\n\nThis is also very basic, for now. This is just boiler plate you need to follow along when the good stuff comes.\n\n```dart\nclass HomeScreen extends StatefulWidget {\n  @override\n  HomeScreenState createState() => new HomeScreenState();\n}\n\nclass HomeScreenState extends State<HomeScreen> {\n  \n  Widget get _logInPrompt {\n    return new Center(\n      child: new Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        crossAxisAlignment: CrossAxisAlignment.center,\n        children: <Widget>[\n          new Text(\n            'Please add user information',\n            style: const TextStyle(fontSize: 18.0),\n          ),\n        ],\n      ),\n    );\n  }\n  \n  // All this method does is bring up the form page.\n  void _updateUser(BuildContext context) {\n    Navigator.push(\n      context,\n      new MaterialPageRoute(\n        fullscreenDialog: true,\n        builder: (context) {\n          return new UpdateUserScreen();\n        },\n      ),\n    );\n  }\n  \n  @override\n  Widget build(BuildContext context) {\n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text('Inherited Widget Test'),\n      ),\n      body: _logInPrompt,\n      floatingActionButton: new FloatingActionButton(\n        onPressed: () => _updateUser(context),\n        child: new Icon(Icons.edit),\n      ),\n    );\n  }\n}\n```\n\n### 3. The UpdateUserScreen Widget\n\nFinally, a form page that does nothing, for now.\n\n\n```dart\nclass UpdateUserScreen extends StatelessWidget {\n  static final GlobalKey<FormState> formKey = new GlobalKey<FormState>();\n  static final GlobalKey<FormFieldState<String>> firstNameKey =\n  new GlobalKey<FormFieldState<String>>();\n  static final GlobalKey<FormFieldState<String>> lastNameKey =\n  new GlobalKey<FormFieldState<String>>();\n  static final GlobalKey<FormFieldState<String>> emailKey =\n  new GlobalKey<FormFieldState<String>>();\n\n  const UpdateUserScreen({Key key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    \n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text('Edit User Info'),\n      ),\n      body: new Padding(\n        padding: new EdgeInsets.all(16.0),\n        child: new Form(\n          key: formKey,\n          autovalidate: false,\n          child: new ListView(\n            children: [\n              new TextFormField(\n                key: firstNameKey,\n                style: Theme.of(context).textTheme.headline,\n                decoration: new InputDecoration(\n                  hintText: 'First Name',\n                ),\n              ),\n              new TextFormField(\n                key: lastNameKey,\n                style: Theme.of(context).textTheme.headline,\n                decoration: new InputDecoration(\n                  hintText: 'Last Name',\n                ),\n              ),\n              new TextFormField(\n                key: emailKey,\n                style: Theme.of(context).textTheme.headline,\n                decoration: new InputDecoration(\n                  hintText: 'Email Address',\n                ),\n              )\n            ],\n          ),\n        ),\n      ),\n      floatingActionButton: new FloatingActionButton(\n        child: new Icon(Icons.add),\n        onPressed: () {\n          final form = formKey.currentState;\n          if (form.validate()) {\n            var firstName = firstNameKey.currentState.value;\n            var lastName = lastNameKey.currentState.value;\n            var email = emailKey.currentState.value;\n\n            // Later, do some stuff here\n\n            Navigator.pop(context);\n          }\n        },\n      ),\n    );\n  }\n}\n```\n[Here's a GitHub Gist of the boiler plate.](https://gist.github.com/ericwindmill/32e73cc1fbf65114b5aa875500395f5a)\n\n##Pt 2: Add in Inherited Widget Functionality\n\n\n\n### 1. StateContainer and InheritedStateContainer Widgets\n\nMake a new file called `state_container.dart`. This is where all things happen.\n\nFirst, in that file, create a simple class called `User`. In a real app, this could be a bigger class called \n`AppState`, where you'd hold all the properties you want to access across your app.\n\n```dart\nclass User {\n  String firstName;\n  String lastName;\n  String email;\n\n  User(this.firstName, this.lastName, this.email);\n}\n```\n\nThe InheritedWidget works as store by connecting to an StatefulWidget. So your StateContainer is really three classes:\n\n```dart\nclass StateContainer extends StatefulWidget\nclass StateContainerState extends State<StateContainer>\nclass _InheritedStateContainer extends InheritedWidget\n```\n\nThe `InheritedWidget` and the `StateContainer` are the simplest to set up, and once they're set up they don't change.\n The logic mainly lives in `StateContainerState`. Set up the first two:\n \n ```dart\n class _InheritedStateContainer extends InheritedWidget {\n    // Data is your entire state. In our case just 'User' \n   final StateContainerState data;\n    \n   // You must pass through a child and your state.\n   _InheritedStateContainer({\n     Key key,\n     @required this.data,\n     @required Widget child,\n   }) : super(key: key, child: child);\n \n   // This is a built in method which you can use to check if\n   // any state has changed. If not, no reason to rebuild all the widgets\n   // that rely on your state.\n   @override\n   bool updateShouldNotify(_InheritedStateContainer old) => true;\n }\n \n class StateContainer extends StatefulWidget {\n    // You must pass through a child. \n   final Widget child;\n   final User user;\n \n   StateContainer({\n     @required this.child,\n     this.user,\n   });\n \n   // This is the secret sauce. Write your own 'of' method that will behave\n   // Exactly like MediaQuery.of and Theme.of\n   // It basically says 'get the data from the widget of this type.\n   static StateContainerState of(BuildContext context) {\n     return (context.inheritFromWidgetOfExactType(_InheritedStateContainer)\n             as _InheritedStateContainer).data;\n   }\n   \n   @override\n   StateContainerState createState() => new StateContainerState();\n }\n ```\nThat 'of' method should really never do anything else. In fact those two classes can just be left alone forever.\n\n\n### 2. StateContainerState Widget\n\nThis Widget is where all your state and logic *can* live. For this app, you'll simply be able to store and manipulate\n your user.\n \n```dart\nclass StateContainerState extends State<StateContainer> {\n  // Whichever properties you wanna pass around your app as state\n  User user;\n\n  // You can (and probably will) have methods on your StateContainer\n  // These methods are then used through our your app to \n  // change state.\n  // Using setState() here tells Flutter to repaint all the \n  // Widgets in the app that rely on the state you've changed.\n  void updateUserInfo({firstName, lastName, email}) {\n    if (user == null) {\n      user = new User(firstName, lastName, email);\n      setState(() {\n        user = user;\n      });\n    } else {\n      setState(() {\n        user.firstName = firstName ?? user.firstName;\n        user.lastName = lastName ?? user.lastName;\n        user.email = email ?? user.email;\n      });\n    }\n  }\n\n  // Simple build method that just passes this state through\n  // your InheritedWidget\n  @override\n  Widget build(BuildContext context) {\n    return new _InheritedStateContainer(\n      data: this,\n      child: widget.child,\n    );\n  }\n}\n``` \n\nIf you've used Redux in the past, you can see how much less boiler plate is involved here. Theres far less opinions, \nwhich of course comes with potential for bugs, but for a simple app, this is fantastic. This is literally *all* the \nwork it takes to set up your Store. Then you just add properties and methods to that class as you need them.\n\n### 3. Refactor Home and Form screens\n\nFirst, wrap your app in the StateContainer:\n\n```dart\nvoid main() {\n  runApp(new StateContainer(child: new UserApp()));\n}\n```\n\nThat's it: now you can access your store all over the app. So do that:\n\n```dart\n// main.dart\n// ... \nclass HomeScreenState extends State<HomeScreen> {\n  // Make a class property for the data you want\n  User user;\n\n  // This Widget will display the users info:\n  Widget get _userInfo {\n    return new Center(\n      child: new Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        crossAxisAlignment: CrossAxisAlignment.center,\n        children: <Widget>[\n          // This refers to the user in your store\n          new Text(\"${user.firstName} ${user.lastName}\",\n              style: new TextStyle(fontSize: 24.0)),\n          new Text(user.email, style: new TextStyle(fontSize: 24.0)),\n        ],\n      ),\n    );\n  }\n\n  Widget get _logInPrompt {\n    // ...\n  }\n\n  void _updateUser(BuildContext context) {\n    // ...\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    // This is how you access your store. This container\n    // is where your properties and methods live\n    final container = StateContainer.of(context);\n    \n    // set the class's user\n    user = container.user;\n    \n    var body = user != null ? _userInfo : _logInPrompt;\n    \n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text('Inherited Widget Test'),\n      ),\n      // The body will rerender to show user info\n      // as its updated\n      body: body,\n      floatingActionButton: new FloatingActionButton(\n        onPressed: () => _updateUser(context),\n        child: new Icon(Icons.edit),\n      ),\n    );\n  }\n}\n```\n\nPretty simple changes there. And the form page isn't much different:\n\n```dart\n// form_page.dart\n// ...\nclass UpdateUserScreen extends StatelessWidget {\n  // ...\n\n  @override\n  Widget build(BuildContext context) {\n    // get reference to your store\n    final container = StateContainer.of(context);\n    \n    return new Scaffold(\n      // the form is the same until here:\n      floatingActionButton: new FloatingActionButton(\n        child: new Icon(Icons.add),\n        onPressed: () {\n          final form = formKey.currentState;\n          if (form.validate()) {\n            var firstName = firstNameKey.currentState.value;\n            var lastName = lastNameKey.currentState.value;\n            var email = emailKey.currentState.value;\n\n            // This is a hack that isn't important\n            // To this lesson. Basically, it prevents \n            // The store from overriding user info\n            // with an empty string if you only want\n            // to change a single attribute\n            if (firstName == '') {\n              firstName = null;\n            }\n            if (lastName == '') {\n              lastName = null;\n            }\n            if (email == '') {\n              email = null;\n            }\n\n            // You can call the method from your store,\n            // which will call set state and rerender\n            // the widgets that rely on the user slice of state.\n            // In this case, thats the home page\n            container.updateUserInfo(\n              firstName: firstName,\n              lastName: lastName,\n              email: email,\n            );\n            \n            Navigator.pop(context);\n          }\n        },\n      ),\n    );\n  }\n}\n\n```\n\n\nThat's it! The InheritedWidget is easy, and an extremely viable option for simple apps, prototypes, etc.\n\n[Here are the completed files on GitHub Gist](https://gist.github.com/ericwindmill/f790bd2456e6489b1ab97eba246fd4c6)\n","created_at":"2020-07-21T16:15:57.541Z","id":68,"slug":"inherited-widgets","title":"Inherited Widgets","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},{"author":1,"content":"*Widgets* are building blocks which you, the developer, will compose together to make a UI. When learning Flutter, you'll hear the phrase \"everything is a widget\" quite often. For our purposes now, that's true. Every object in your Flutter application's UI is a widget. Structure is defined with widgets, styles are defined with widgets, even animations and routing is handled by widgets. And, widgets are just Dart classes that know how to describe their view.\n\nIn the image below, a few of the widgets on-screen are highlighted.\n\n<img src=\"counter_app_annotated.png\" alt=\"drawing\" style=\"width:400px;\"/>\n\nThese are some of the most basic widgets, but there are a lot of implications here. First, you have a `Text` widget and a `Button` widget. These represent tangible pieces of UI. But, notice that there's also a `Column` widget. This widget tells other widgets to arrange themselves vertically. Importantly, there's no CSS or styling language, it's just widgets.\n\n\n### Built in Widgets\n\nThe above image shows the \"counter app\", which is the default application that's built when you start a new Flutter project. Which means that everything on that screen is built into Flutter. \n\nFlutter offers several widgets out of the box, which we, the Flutter developers, will combine to make custom widgets and robust UI. Here are just a few of the most basic built in widgets in Flutter, separated by their use.\n\n* _Layout_--`Row`, `Column`, `Scaffold`, `Stack`\n* _Structures_--`Button`, `Toast`, `MenuDrawer`\n* _Styles_--`TextStyle`, `Color`\n* _Animations_--`FadeInPhoto`, transformations\n* _Positioning and alignment_--`Center`, `Padding`\n\n### Writing a widget in code\n\nMost of the Flutter code you write will be creating custom widgets. Widgets are just Dart class that _extend_ a `Widget` class. Suppose you wanted to make a button widget with custom styling. This is how you'd define the class:\n\n```dart\nclass AlertButton extends StatelessWidget {\n  // class members\n}\n```\n\n<div class=\"aside\">\nThe class `StatelessWidget` is the most basic widget class, and the one you'll use the most often. We'll cover the different types of widgets later.\n</div>\n\n\nWhen creating widgets, there is one requirement enforced by the widget superclass. It must have a `build` method. This method must return other widgets. It's the method that you use to compose widgets together to make a UI.\n\nUsing that same `AlertButton` example:\n\n```dart\nclass AlertButton extends StatelessWidget {\n\n  @override\n  Widget build(BuildContext context) {\n    return RaisedButton(\n      color: Colors.red,\n      child: Text(\"Alert!\")\n    );\n  } \n}\n``` \n\nOther than the `build` method, Widgets are just like any other Dart class. You can add methods and properties to the widget classes.\n\n```dart\nclass AlertButton extends StatelessWidget {\n  // a property on this class\n  final String text;\n\n  // a constructor for this class\n  AlertButton(this.text);\n\n  @override\n  Widget build(BuildContext context) {\n    return RaisedButton(\n      color: Colors.red,\n      child: Text(text), // use the text passed in to the constructor.\n    );\n  } \n}\n``` \n\n\n","created_at":"2020-07-21T16:12:22.302Z","id":63,"slug":"intro-to-widgets","title":"Intro to Widgets","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"}]},"strapiTableOfContents":{"contents":"{\n  \"Dart\": {\n    \"Getting Started with Dart\": [\n      \"About Dart\",\n      \"Install Dart on your machine\",\n      \"Dartpad\",\n      \"Text Editors: Intellij and VSCode\",\n      \"Resources: Documentation and Pub.dev\",\n      \"Hello World\",\n      \"The main function\",\n      \"Print to the console\"\n    ],\n    \"Dart Fundamentals\": [\n      \"Values and variables\",\n      \"Comments\",\n      \"const and final variables\",\n      \"Arithmetic and Comparison Operators\",\n      \"Assignment Operators\",\n      \"Logical Operators\",\n      \"Null Aware Operators\",\n      \"Type Test Operators\",\n      \"Bitwise and Shift Operators\",\n      \"Control Flow: if, else, else if\",\n      \"Switch statements and case\",\n      \"Ternary Conditional operator\",\n      \"Loops: for and while\",\n      \"Anatomy of Dart Functions\",\n      \"Arrow functions\",\n      \"Function arguments: default, optional, named\",\n      \"Lexical Scope\",\n      \"Cascade notation\"\n    ],\n    \"Data Types\": [\n      \"Intro to Dart's Type System\",\n      \"Numbers\",\n      \"Strings\",\n      \"Booleans\",\n      \"dynamic\",\n      \"lists\",\n      \"sets\",\n      \"maps\"\n    ],\n    \"Object-Oriented Programming\": [\n      \"Intro to OOP\",\n      \"Classes\",\n      \"Constructors\",\n      \"Properties and methods\",\n      \"Methods: static, private, etc\",\n      \"Getters and setters\",\n      \"Extending classes (inheritance)\",\n      \"Initializer lists and final properties\",\n      \"Factory methods\",\n      \"Singletons\",\n      \"Abstract classes (and interfaces)\",\n      \"Mixins\",\n      \"Extension methods\"\n    ],\n    \"Iterables, Iterators, and Collections\": [\n      \"What are collections (and iterables)?\",\n      \"Looping: for-in and forEach\",\n      \"Reading elements pt 1: first, last\",\n      \"Adding elements: add and insert (all)\",\n      \"Checking for elements: contains, indexOf, any, every\",\n      \"Removing elements: remove, clear, removeWhere\",\n      \"Filtering elements: where, takeWhile, and skipWhile\",\n      \"Changing elements: map and expand\",\n      \"Deriving values from elements: fold, reduce, join\",\n      \"Type casting collections: cast, as, retype, toSet, toList\",\n      \"Iterators: understanding and creating your own\",\n      \"Iterable-like methods on maps (and putIfAbsent)\"\n    ]\n  },\n  \"Flutter\": {\n    \"Getting started with Flutter\": [\n      \"About Flutter\",\n      \"IDEs and resources\"\n    ],\n    \"Widgets\": [\n      \"Intro to Widgets\",\n      \"Widget types: Stateful and Stateless\",\n      \"StatefulWidget lifecycle\",\n      \"The Widget tree\",\n      \"BuildContext\",\n      \"Inherited Widgets\",\n      \"Thinking in widgets\"\n    ],\n    \"Intro Flutter App\": [\n      \"Intro and Setup\",\n      \"Data Model and HTTP\",\n      \"Build a custom widget\",\n      \"ListView and builder pattern\",\n      \"Gradient Backgrounds\",\n      \"Routing: Add a detail page\",\n      \"Routing 2: Add a form page\",\n      \"User Input\",\n      \"Sliders and Buttons\",\n      \"Snackbars and Dialogs\",\n      \"Built-in Animation: AnimatedCrossFade\",\n      \"Built-in Animation: Hero transition\"\n    ],\n    \"Custom Animation: Progress Indicator\": [\n      \"Intro and Overview\",\n      \"Build the example app boiler-plate\",\n      \"Custom Widget: Peg\",\n      \"Tween and AnimationController classes\",\n      \"Tween by example\",\n      \"Using Tweens and Intervals\",\n      \"Wrap the Pegs in AnimatedWidgets\",\n      \"Bring it all together\"\n    ],\n    \"State Management: Blocs without Libraries\": [\n      \"What are blocs?\",\n      \"Calendar App introduction\",\n      \"Create bloc one\",\n      \"Create a bloc provider\",\n      \"Using StreamBuilders with blocs\",\n      \"Create bloc two: Add/Edit Tasks\",\n      \"Consume the second bloc's streams\",\n      \"Complete source code\"\n    ],\n    \"State Management: Provider\": [\n      \"What is Provider?\",\n      \"The most basic example using Provider\",\n      \"ChangeNotifierProvider\",\n      \"Rebuilding widgets with Consumer\",\n      \"Finer build control with Selector\",\n      \"Future Provider\",\n      \"MultiProvider micro lesson\",\n      \"Stream Provider\",\n      \"Using context extensions for more control\",\n      \"ProxyProvider\",\n      \"Using .value constructors\",\n      \"The final example (A shopping cart app)\",\n      \"For the curious: How is provider implemented\"\n    ],\n    \"Handling Data with Brick: Offline First with Rest\": [\n      \"About Brick and setup\",\n      \"Adding a Repository\",\n      \"Adding a Model\",\n      \"Generating Code\",\n      \"Rendering Models\",\n      \"Adding an Association\"\n    ]\n  }\n}"}},"pageContext":{"slug":"intro-to-widgets","tutorialTitle":"Widgets","previous":{"author":1,"content":"If you've used Flutter before, you've probably come across the 'of' method on different classes here and there:\n\n```dart\nTheme.of(context).textTheme\nMediaQuery.of(context).size\n```\n\nThose widgets (Theme, MediaQuery) are Inherited widgets. Pretty much anywhere in your app, you can access your theme,\n because they're inherited.\n \nIn Flutter, every part of the sdk is exposed to the developer, so you can take advantage of the inherited widget \nyourself. You can use a custom InheritedWidget as a built-in central state storage, similar to a Redux Store or Vue's \nVuex Store.\n\nAfter you've set up a store like this, you'll be able to do something like this: \n\n```dart\nclass RedText extends StatelessWidget {\n  // ...\n  Widget build(BuildContext context) {\n    var state = StateContainer.of(context).state;\n    return new Text(\n      state.user.username,\n      style: const TextStyle(color: Colors.red),\n    );\n  // ...\n```\n\n### Lifting State Up\n\nWhen using an InheritedWidget as your state management tool, you're likely relying on an architecture pattern called \n'Lifting State Up'. \n\nConsider the starter Flutter app when you start a new project (the counter app). If you wanted to\n separate that app into two pages, one that displayed the counter, and one that allowed you to change the number. \n Suddenly, this incredibly simple app is confusing. Each time you change routes, you have to be passing this piece of\n  state (the counter) back and forth.\n  \nThe InheritedWidget solves this problem by giving an entire widget tree access to the same pieces of state. \n\n <img src=\"http://res.cloudinary.com/ericwindmill/image/upload/v1518974500/flutter_by_example/medium_tree.png\" />\n\nFor a super awesome detailed explanation of different Flutter architecture concepts, [watch Brain Egan's talk from \nDartConf 2018](https://www.youtube.com/watch?v=zKXz3pUkw9A&t=1467s). Just don't watch too much, or you'll be \nconvinced to use [flutter_redux](https://pub.dartlang.org/packages/flutter_redux), and you won't care about this article anymore. 🙃\n\nThe advantage to lifting state up rather than reaching for something like Redux, is that using an Inherited Widget is\n pretty simple to set up and use. \n \n**NB:** To be sure, I am a fan of Redux and Vuex and all the 'ux' things. This is just another tool in your toolbox \nfor when Redux is more than you need. \n\n### Why Bother?\n\nAt this point, you might be asking why you should bother with an InheritedWidget. Why not just stick with a stateful \nwidget at the apps root? \n\nWell really, that's what you are doing here. The inherited widget works in conjunction with a stateful widget and \nallows you to pass that StatefulWidgets state to *all* of its ancestors. Its a convenience widget. So you don't have \nto type the code in every class to pass state down to its children.\n\n##Pt: 1 Set up a boiler plate app\n\nFor this example, let's just make this simple app:\n\n<img src=\"http://res.cloudinary.com/ericwindmill/image/upload/v1523742041/blog_posts/inherited_test.gif\" />\n\nBasically this app's state is lifted up above the root Widget, and when you submit the form, it calls `setState` on \nthat inherited widgets state, which tells the main page that there's new information to render.\n\n### 1. The Material App Root\n\nThis is just your standard Flutter app set up:\n\n```dart\nvoid main() {\n  runApp(new UserApp());\n}\n\nclass UserApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return new MaterialApp(\n      home: new HomeScreen(),\n    );\n  }\n}\n```\n\n### 2. HomeScreen Widget\n\nThis is also very basic, for now. This is just boiler plate you need to follow along when the good stuff comes.\n\n```dart\nclass HomeScreen extends StatefulWidget {\n  @override\n  HomeScreenState createState() => new HomeScreenState();\n}\n\nclass HomeScreenState extends State<HomeScreen> {\n  \n  Widget get _logInPrompt {\n    return new Center(\n      child: new Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        crossAxisAlignment: CrossAxisAlignment.center,\n        children: <Widget>[\n          new Text(\n            'Please add user information',\n            style: const TextStyle(fontSize: 18.0),\n          ),\n        ],\n      ),\n    );\n  }\n  \n  // All this method does is bring up the form page.\n  void _updateUser(BuildContext context) {\n    Navigator.push(\n      context,\n      new MaterialPageRoute(\n        fullscreenDialog: true,\n        builder: (context) {\n          return new UpdateUserScreen();\n        },\n      ),\n    );\n  }\n  \n  @override\n  Widget build(BuildContext context) {\n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text('Inherited Widget Test'),\n      ),\n      body: _logInPrompt,\n      floatingActionButton: new FloatingActionButton(\n        onPressed: () => _updateUser(context),\n        child: new Icon(Icons.edit),\n      ),\n    );\n  }\n}\n```\n\n### 3. The UpdateUserScreen Widget\n\nFinally, a form page that does nothing, for now.\n\n\n```dart\nclass UpdateUserScreen extends StatelessWidget {\n  static final GlobalKey<FormState> formKey = new GlobalKey<FormState>();\n  static final GlobalKey<FormFieldState<String>> firstNameKey =\n  new GlobalKey<FormFieldState<String>>();\n  static final GlobalKey<FormFieldState<String>> lastNameKey =\n  new GlobalKey<FormFieldState<String>>();\n  static final GlobalKey<FormFieldState<String>> emailKey =\n  new GlobalKey<FormFieldState<String>>();\n\n  const UpdateUserScreen({Key key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    \n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text('Edit User Info'),\n      ),\n      body: new Padding(\n        padding: new EdgeInsets.all(16.0),\n        child: new Form(\n          key: formKey,\n          autovalidate: false,\n          child: new ListView(\n            children: [\n              new TextFormField(\n                key: firstNameKey,\n                style: Theme.of(context).textTheme.headline,\n                decoration: new InputDecoration(\n                  hintText: 'First Name',\n                ),\n              ),\n              new TextFormField(\n                key: lastNameKey,\n                style: Theme.of(context).textTheme.headline,\n                decoration: new InputDecoration(\n                  hintText: 'Last Name',\n                ),\n              ),\n              new TextFormField(\n                key: emailKey,\n                style: Theme.of(context).textTheme.headline,\n                decoration: new InputDecoration(\n                  hintText: 'Email Address',\n                ),\n              )\n            ],\n          ),\n        ),\n      ),\n      floatingActionButton: new FloatingActionButton(\n        child: new Icon(Icons.add),\n        onPressed: () {\n          final form = formKey.currentState;\n          if (form.validate()) {\n            var firstName = firstNameKey.currentState.value;\n            var lastName = lastNameKey.currentState.value;\n            var email = emailKey.currentState.value;\n\n            // Later, do some stuff here\n\n            Navigator.pop(context);\n          }\n        },\n      ),\n    );\n  }\n}\n```\n[Here's a GitHub Gist of the boiler plate.](https://gist.github.com/ericwindmill/32e73cc1fbf65114b5aa875500395f5a)\n\n##Pt 2: Add in Inherited Widget Functionality\n\n\n\n### 1. StateContainer and InheritedStateContainer Widgets\n\nMake a new file called `state_container.dart`. This is where all things happen.\n\nFirst, in that file, create a simple class called `User`. In a real app, this could be a bigger class called \n`AppState`, where you'd hold all the properties you want to access across your app.\n\n```dart\nclass User {\n  String firstName;\n  String lastName;\n  String email;\n\n  User(this.firstName, this.lastName, this.email);\n}\n```\n\nThe InheritedWidget works as store by connecting to an StatefulWidget. So your StateContainer is really three classes:\n\n```dart\nclass StateContainer extends StatefulWidget\nclass StateContainerState extends State<StateContainer>\nclass _InheritedStateContainer extends InheritedWidget\n```\n\nThe `InheritedWidget` and the `StateContainer` are the simplest to set up, and once they're set up they don't change.\n The logic mainly lives in `StateContainerState`. Set up the first two:\n \n ```dart\n class _InheritedStateContainer extends InheritedWidget {\n    // Data is your entire state. In our case just 'User' \n   final StateContainerState data;\n    \n   // You must pass through a child and your state.\n   _InheritedStateContainer({\n     Key key,\n     @required this.data,\n     @required Widget child,\n   }) : super(key: key, child: child);\n \n   // This is a built in method which you can use to check if\n   // any state has changed. If not, no reason to rebuild all the widgets\n   // that rely on your state.\n   @override\n   bool updateShouldNotify(_InheritedStateContainer old) => true;\n }\n \n class StateContainer extends StatefulWidget {\n    // You must pass through a child. \n   final Widget child;\n   final User user;\n \n   StateContainer({\n     @required this.child,\n     this.user,\n   });\n \n   // This is the secret sauce. Write your own 'of' method that will behave\n   // Exactly like MediaQuery.of and Theme.of\n   // It basically says 'get the data from the widget of this type.\n   static StateContainerState of(BuildContext context) {\n     return (context.inheritFromWidgetOfExactType(_InheritedStateContainer)\n             as _InheritedStateContainer).data;\n   }\n   \n   @override\n   StateContainerState createState() => new StateContainerState();\n }\n ```\nThat 'of' method should really never do anything else. In fact those two classes can just be left alone forever.\n\n\n### 2. StateContainerState Widget\n\nThis Widget is where all your state and logic *can* live. For this app, you'll simply be able to store and manipulate\n your user.\n \n```dart\nclass StateContainerState extends State<StateContainer> {\n  // Whichever properties you wanna pass around your app as state\n  User user;\n\n  // You can (and probably will) have methods on your StateContainer\n  // These methods are then used through our your app to \n  // change state.\n  // Using setState() here tells Flutter to repaint all the \n  // Widgets in the app that rely on the state you've changed.\n  void updateUserInfo({firstName, lastName, email}) {\n    if (user == null) {\n      user = new User(firstName, lastName, email);\n      setState(() {\n        user = user;\n      });\n    } else {\n      setState(() {\n        user.firstName = firstName ?? user.firstName;\n        user.lastName = lastName ?? user.lastName;\n        user.email = email ?? user.email;\n      });\n    }\n  }\n\n  // Simple build method that just passes this state through\n  // your InheritedWidget\n  @override\n  Widget build(BuildContext context) {\n    return new _InheritedStateContainer(\n      data: this,\n      child: widget.child,\n    );\n  }\n}\n``` \n\nIf you've used Redux in the past, you can see how much less boiler plate is involved here. Theres far less opinions, \nwhich of course comes with potential for bugs, but for a simple app, this is fantastic. This is literally *all* the \nwork it takes to set up your Store. Then you just add properties and methods to that class as you need them.\n\n### 3. Refactor Home and Form screens\n\nFirst, wrap your app in the StateContainer:\n\n```dart\nvoid main() {\n  runApp(new StateContainer(child: new UserApp()));\n}\n```\n\nThat's it: now you can access your store all over the app. So do that:\n\n```dart\n// main.dart\n// ... \nclass HomeScreenState extends State<HomeScreen> {\n  // Make a class property for the data you want\n  User user;\n\n  // This Widget will display the users info:\n  Widget get _userInfo {\n    return new Center(\n      child: new Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        crossAxisAlignment: CrossAxisAlignment.center,\n        children: <Widget>[\n          // This refers to the user in your store\n          new Text(\"${user.firstName} ${user.lastName}\",\n              style: new TextStyle(fontSize: 24.0)),\n          new Text(user.email, style: new TextStyle(fontSize: 24.0)),\n        ],\n      ),\n    );\n  }\n\n  Widget get _logInPrompt {\n    // ...\n  }\n\n  void _updateUser(BuildContext context) {\n    // ...\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    // This is how you access your store. This container\n    // is where your properties and methods live\n    final container = StateContainer.of(context);\n    \n    // set the class's user\n    user = container.user;\n    \n    var body = user != null ? _userInfo : _logInPrompt;\n    \n    return new Scaffold(\n      appBar: new AppBar(\n        title: new Text('Inherited Widget Test'),\n      ),\n      // The body will rerender to show user info\n      // as its updated\n      body: body,\n      floatingActionButton: new FloatingActionButton(\n        onPressed: () => _updateUser(context),\n        child: new Icon(Icons.edit),\n      ),\n    );\n  }\n}\n```\n\nPretty simple changes there. And the form page isn't much different:\n\n```dart\n// form_page.dart\n// ...\nclass UpdateUserScreen extends StatelessWidget {\n  // ...\n\n  @override\n  Widget build(BuildContext context) {\n    // get reference to your store\n    final container = StateContainer.of(context);\n    \n    return new Scaffold(\n      // the form is the same until here:\n      floatingActionButton: new FloatingActionButton(\n        child: new Icon(Icons.add),\n        onPressed: () {\n          final form = formKey.currentState;\n          if (form.validate()) {\n            var firstName = firstNameKey.currentState.value;\n            var lastName = lastNameKey.currentState.value;\n            var email = emailKey.currentState.value;\n\n            // This is a hack that isn't important\n            // To this lesson. Basically, it prevents \n            // The store from overriding user info\n            // with an empty string if you only want\n            // to change a single attribute\n            if (firstName == '') {\n              firstName = null;\n            }\n            if (lastName == '') {\n              lastName = null;\n            }\n            if (email == '') {\n              email = null;\n            }\n\n            // You can call the method from your store,\n            // which will call set state and rerender\n            // the widgets that rely on the user slice of state.\n            // In this case, thats the home page\n            container.updateUserInfo(\n              firstName: firstName,\n              lastName: lastName,\n              email: email,\n            );\n            \n            Navigator.pop(context);\n          }\n        },\n      ),\n    );\n  }\n}\n\n```\n\n\nThat's it! The InheritedWidget is easy, and an extremely viable option for simple apps, prototypes, etc.\n\n[Here are the completed files on GitHub Gist](https://gist.github.com/ericwindmill/f790bd2456e6489b1ab97eba246fd4c6)\n","created_at":"2020-07-21T16:15:57.541Z","id":68,"slug":"inherited-widgets","title":"Inherited Widgets","tutorial":7,"updated_at":"2020-07-24T16:55:59.133Z"},"next":null}},"staticQueryHashes":["2185715291","3564968493","63159454"]}