<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Martin Rybak on Medium]]></title>
        <description><![CDATA[Stories by Martin Rybak on Medium]]></description>
        <link>https://medium.com/@martinrybak?source=rss-a53992d973c9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*x2njdNyfGtnfXrsh.jpeg</url>
            <title>Stories by Martin Rybak on Medium</title>
            <link>https://medium.com/@martinrybak?source=rss-a53992d973c9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 14:49:47 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@martinrybak/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[A Deep Dive into the Flutter Animations package]]></title>
            <link>https://medium.com/flutter-nyc/a-deep-dive-into-the-flutter-animations-package-3e26b10c43c1?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/3e26b10c43c1</guid>
            <category><![CDATA[material-design]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[app-development]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Tue, 25 Feb 2020 14:39:16 GMT</pubDate>
            <atom:updated>2020-02-25T14:39:16.730Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1ByzGmTsEctIH4MP6Cuhzw.jpeg" /></figure><p>An overview of Google’s new Material Design <a href="https://material.io/design/motion/the-motion-system.html">motion system</a>, plus examples of the new Flutter <a href="https://pub.dev/packages/animations">animations</a> package.</p><p>On February 21, 2020, the Flutter team launched the <a href="https://pub.dev/packages/animations">animations</a> package as part of Google’s newly announced <a href="https://material.io/design/motion/the-motion-system.html">Material Design motion system</a>. This package lets Flutter developers implement commonly used animations and transition patterns in their apps much more easily than before. In this post, we’ll go over the motion system and show how to use the <a href="https://pub.dev/packages/animations">animations</a> package to create those new transitions in Flutter. We also see how they fit into existing usages of the <a href="https://pub.dev/documentation/animations/latest/animations/showModal.html">Navigator</a> and <a href="https://api.flutter.dev/flutter/widgets/Hero-class.html">Hero</a> widgets.</p><h3><strong>An overview of the Material Design motion system</strong></h3><p><a href="https://material.io/">Material Design</a> is a platform-agnostic design system from Google that comes with native iOS, Android, web, and Flutter implementations. The <a href="https://material.io/design/motion/the-motion-system.html">motion system</a> is a new addition to Material Design and consists of four transition patterns that help users understand and navigate through an app:</p><ol><li><a href="https://material.io/design/motion/the-motion-system.html#container-transform">Container transform</a></li><li><a href="https://material.io/design/motion/the-motion-system.html#shared-axis">Shared Axis</a></li><li><a href="https://material.io/design/motion/the-motion-system.html#fade-through">Fade through</a></li><li><a href="https://material.io/design/motion/the-motion-system.html#fade">Fade</a></li></ol><h4><strong>Container transform</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*RH1BDH4i2s9iBYPzVIuHEQ.gif" /><figcaption>The Material Design <a href="https://material.io/design/motion/the-motion-system.html#container-transform">Container</a> transform.</figcaption></figure><p>Nearly every app uses the master-detail pattern, such as navigating from of a list view to a detail view. This is where the <a href="https://material.io/design/motion/the-motion-system.html#container-transform">Container</a> transform is well suited. By seamlessly transforming a list tile into a detail page, the relationship between the two components is maintained. As long as there is an enclosed area that acts as a <a href="https://material.io/design/motion/choreography.html#sequencing">persistent element</a> in the transition, it is a good candidate for the Container transform. Other examples are the transition of a search bar into an expanded search page with more options and filters, and a <a href="https://api.flutter.dev/flutter/material/Chip-class.html">Chip</a> into an expanded chip. The Container transform does <em>not</em> strictly have to be full-screen; it can also apply in scenarios where a smaller component expands into a larger one.</p><h4><strong>Shared Axis</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*AaQviXU_WvuAkJq9xZicuQ.gif" /><figcaption>The Material Design <a href="https://material.io/design/motion/the-motion-system.html#shared-axis">Shared Axis</a> pattern.</figcaption></figure><p>The <a href="https://material.io/design/motion/the-motion-system.html#shared-axis">Shared Axis</a> pattern can be used if the elements in a transition do not have a persistent container, but still share a common navigational or horizontal/vertical layout. A good example is the forward and backward navigation in a typical onboarding flow. In this case, the Shared Axis pattern adds a horizontal translation plus a fade-in and fade-out to each page transition. The translation is not limited to the x-axis; it can be applied to the y-axis (vertical), or z-axis (depth) as well.</p><h4><strong>Fade through</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*MNhg2TWVclpnqwsTwGCyLQ.gif" /><figcaption>The Material Design <a href="https://material.io/design/motion/the-motion-system.html#fade-through">Fade through</a> pattern.</figcaption></figure><p>The <a href="https://material.io/design/motion/the-motion-system.html#fade-through">Fade through</a> pattern applies to scenarios where UI components do not necessarily have a strong spatial or navigational relationship with each other. This pattern replaces content in-place with a combination fade and scale transition. This is useful when there is a substantial change to the content being displayed. For example, when tapping on a refresh button to reload data on a screen. When the UI updates, the fade and scale effect gives the user the impression that the data was changed substantially.</p><h4><strong>Fade</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*nD2U-JrT1iV6IWQ0B0PgkQ.gif" /><figcaption>The Material Design <a href="https://material.io/design/motion/the-motion-system.html#fade">Fade</a> transition.</figcaption></figure><p>The <a href="https://material.io/design/motion/the-motion-system.html#fade">Fade</a> transition applies to scenarios where a UI element simply enters or exits the screen, unlike the <a href="https://material.io/design/motion/the-motion-system.html#fade-through">Fade through</a> transition where the UI elements appear to update in-place. This is also accomplished using a fade and scale animation, but can also be repositioned to appear to emerge from a particular part of the screen. By default, the transition scales from the center. A good use case for this transition is the presentation of a dialog or drop-down menu that would be jarring if it appeared immediately.</p><h3><strong>The Flutter animations package</strong></h3><p>As a first-class citizen in Material Design, we are pleased that Flutter had support for the new motion system on day 1 via the <a href="https://pub.dev/packages/animations">animations</a> package! This is a first-party package from the Flutter team and is available on <a href="https://pub.dev/">pub.dev</a>. Let’s dive into some code and figure out how to use it.</p><h4>Container transform</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*ln0hh81hmiqA6pfhOeuczw.gif" /></figure><p>The new Material Design <a href="https://material.io/design/motion/the-motion-system.html#container-transform">Container transform</a> is implemented in Flutter using the <a href="https://pub.dev/documentation/animations/latest/animations/OpenContainer-class.html">OpenContainer</a> widget. It transitions between two child widgets seamlessly so that they appear to be the same widget. The children are provided via the closedBuilder and openBuilder properties. These builder functions provide a standard <a href="https://api.flutter.dev/flutter/widgets/BuildContext-class.html">BuildContext</a> as well as an additional action callback, which is used to trigger the animation to open and close the widget. There is also a tappable parameter (which defaults to true) which can trigger the “open” transition on tap as an alternative to the action callback. Note that it does <em>not</em> also trigger the “closed” animation.</p><p>We can specify the color, elevation, and shape of the closed and open states, and Flutter will seamlessly interpolate between them. You can alter the transition duration as well as the transition type. The ContainerTransitionType.fade value overlaps the widgets in a cross fade; the ContainerTransitionType.fadeTrough value staggers the widget fades so that they do not overlap.</p><p>It is important to note that the <a href="https://pub.dev/documentation/animations/latest/animations/OpenContainer-class.html">OpenContainer</a> widget must be used in a context with a <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a>. When it transitions from the closed widget to the open widget, it pushes a new <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a> onto its closest ancestor <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a>. It then grows the open widget to fill the entire size of this <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a>. Most Navigators are full-screen, but don’t have to be. Here is an example that generates the GIF above:</p><pre><strong>OpenContainer</strong>(<br>  closedColor: Colors.blue,<br>  openColor: Colors.yellow,<br>  closedElevation: 10.0,<br>  openElevation: 15.0,<br>  closedShape: const RoundedRectangleBorder(<br>    borderRadius: BorderRadius.all(Radius.circular(10.0)),<br>  ),<br>  transitionType: ContainerTransitionType.fade,<br>  transitionDuration: const Duration(milliseconds: 500),<br>  openBuilder: (context, action) {<br>    return DetailsPage();<br>  },<br>  closedBuilder: (context, action) {<br>   return const ExampleCard();<br> },<br>);</pre><h4>Shared axis</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*q70HQkR5o1xs0-7vzQktew.gif" /></figure><p>The new Material Design <a href="https://material.io/design/motion/the-motion-system.html#shared-axis">Shared Axis</a> transition is implemented in Flutter using the <a href="https://pub.dev/documentation/animations/latest/animations/SharedAxisTransition-class.html">SharedAxisTransition</a> widget. It generates a shared translation + fade transition in either the x, y, or z axis. It accepts a child widget as a parameter. The animation between the “old” and “new” child widgets is controlled by the animation and secondaryAnimation parameters. This means that the <a href="https://pub.dev/documentation/animations/latest/animations/SharedAxisTransition-class.html">SharedAxisTransition</a> widget can’t live on its own and must be “driven” by an outside source. One such source is the new <a href="https://pub.dev/documentation/animations/latest/animations/PageTransitionSwitcher-class.html">PageTransitionSwitcher</a> widget, which is part of the <a href="https://pub.dev/packages/animations">animations</a> package and is used to align transitions between widgets. This widget is similar to the <a href="https://api.flutter.dev/flutter/widgets/widgets/AnimatedSwitcher-class.html">AnimatedSwitcher</a> widget, which does a cross-fade between it’s “old” and “new” child, but lets us define the enter and exit animations separately.</p><pre><strong>PageTransitionSwitcher</strong>(<br>  transitionBuilder: (<br>  Widget child,<br>  Animation&lt;double&gt; primaryAnimation,<br>  Animation&lt;double&gt; secondaryAnimation,<br>) {<br>  return <strong>SharedAxisTransition</strong>(<br>    animation: primaryAnimation,<br>    secondaryAnimation: secondaryAnimation,<br>    transitionType: SharedAxisTransitionType.horizontal,<br>    child: child,<br>  );<br> },<br>  child: child,<br>}</pre><p>To use the <a href="https://pub.dev/documentation/animations/latest/animations/SharedAxisTransition-class.html">SharedAxisTransition</a> transition by default for <strong>all</strong> routes inside a <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a>, you can add a <a href="https://api.flutter.dev/flutter/material/PageTransitionsTheme-class.html">PageTransitionsTheme</a> to the <a href="https://api.flutter.dev/flutter/material/ThemeData-class.html">ThemeData</a> of <a href="https://api.flutter.dev/flutter/material/MaterialApp-class.html">MaterialApp</a>. Add a <a href="https://pub.dev/documentation/animations/latest/animations/SharedAxisPageTransitionsBuilder-class.html">SharedAxisPageTransitionsBuilder</a> to the builders property with the desired transition type for every platform where you want this transition to apply:</p><pre>MaterialApp(<br>  theme: ThemeData(<br>    pageTransitionsTheme: PageTransitionsTheme(<br>      builders: {<br>        TargetPlatform.android: SharedAxisPageTransitionsBuilder(<br>          transitionType: SharedAxisTransitionType.horizontal,<br>        ),<br>        TargetPlatform.iOS: SharedAxisPageTransitionsBuilder(<br>          transitionType: SharedAxisTransitionType.horizontal,<br>        ),<br>      },<br>    ),<br>  ),<br>  routes: {<br>    &#39;/&#39;: (BuildContext context) {<br>      <strong>return</strong> Home(...);<br>    },<br>    ...<br>  },<br>);</pre><p>Be careful though — this technique is an all-or-none approach, and it only works for <em>named</em> routes. But what if we want to push routes programmatically onto a <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a>, as in the following example?</p><pre>final route = MaterialPageRoute(builder: (_) =&gt; MyWidget());<br>Navigator.of(context).push(route);</pre><p>This technique helps us better decouple our <strong>content</strong> (MyWidget) from our <strong>transition</strong> (<a href="https://api.flutter.dev/flutter/material/MaterialPageRoute-class.html">MaterialPageRoute</a>). To use the <a href="https://pub.dev/documentation/animations/latest/animations/SharedAxisTransition-class.html">SharedAxisTransition</a> transition, we can just create a new <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a> that consumes it. We can either subclass <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a> or use a <a href="https://api.flutter.dev/flutter/material/widgets/PageRouteBuilder-class.html">PageRouteBuilder</a>:</p><pre>import &#39;package:flutter/material.dart&#39;;<br>import &#39;package:animations/animations.dart&#39;;</pre><pre>class<strong> SharedAxisPageRoute</strong> extends<strong> PageRouteBuilder</strong> {<br>  SharedAxisPageRoute({Widget page, SharedAxisTransitionType transitionType}) : super(<br>    pageBuilder: (<br>      BuildContext context,<br>      Animation&lt;double&gt; primaryAnimation,<br>      Animation&lt;double&gt; secondaryAnimation,<br>    ) =&gt; page,<br>    transitionsBuilder: (<br>      BuildContext context,<br>      Animation&lt;double&gt; primaryAnimation,<br>      Animation&lt;double&gt; secondaryAnimation,<br>      Widget child,<br>    ) {<br>      return<strong> SharedAxisTransition</strong>(<br>        animation: primaryAnimation,<br>        secondaryAnimation: secondaryAnimation,<br>        transitionType: transitionType,<br>        child: child,<br>      );<br>    },<br>  );<br>}</pre><p>Then we can continue to push new screens on our <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a> programmatically:</p><pre>final route = SharedAxisPageRoute(page: myWidget);<br>Navigator.of(context).push(route);</pre><h4>Fade through</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*gOwj6oSg3Z6nwUgm7bd2kA.gif" /></figure><p>The new Material Design <a href="https://material.io/design/motion/the-motion-system.html#fade-through">Fade through</a> transition is implemented in Flutter using the <a href="https://pub.dev/documentation/animations/latest/animations/FadeThroughTransition-class.html">FadeThroughTransition</a> widget. This widget applies a fade transition to the outgoing element and a fade and scale transition to the incoming element. Similar to the <a href="https://pub.dev/documentation/animations/latest/animations/SharedAxisTransition-class.html">SharedAxisTransition</a>, it can also be used inside a <a href="https://pub.dev/documentation/animations/latest/animations/PageTransitionSwitcher-class.html">PageTransitionSwitcher</a> widget, applied globally to all named <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a> routes, or applied selectively to only certain routes via a custom <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a>.</p><h4>Fade</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*VudX_i8xIlyX4DwEK3U3jQ.gif" /></figure><p>The new Material Design <a href="https://material.io/design/motion/the-motion-system.html#fade">Fade</a> transition is implemented in Flutter using the <a href="https://pub.dev/documentation/animations/latest/animations/FadeScaleTransition-class.html">FadeScaleTransition</a> widget. Entering elements fade in with increasing opacity and scale from 80% to 100%, while exiting elements fade out with decreasing opacity. It can also be used inside a <a href="https://pub.dev/documentation/animations/latest/animations/PageTransitionSwitcher-class.html">PageTransitionSwitcher</a> widget, applied globally to all named <a href="https://api.flutter.dev/flutter/widgets/Navigator-class.html">Navigator</a> routes, applied selectively using a custom <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a>, or shown using the new <a href="https://pub.dev/documentation/animations/latest/animations/showModal.html">showModal()</a> method:</p><h4>showModal()</h4><p>The Flutter <a href="https://pub.dev/packages/animations">animations</a> package introduces a new global function called <a href="https://pub.dev/documentation/animations/latest/animations/showModal.html">showModal()</a> which can be used to display content in a modal in the current <a href="https://pub.dev/documentation/animations/latest/animations/showModal.html">Navigator</a>. This is very similar to the existing <a href="https://api.flutter.dev/flutter/widgets/showGeneralDialog.html">showGeneralDialog()</a> function which is part of <a href="https://api.flutter.dev/flutter/material/material-library.html">material.dart</a>. The difference is that the modal configuration properties have been pulled out into a single configuration argument of type <a href="https://pub.dev/documentation/animations/latest/animations/ModalConfiguration-class.html">ModalConfiguration</a>. This class contains various characteristics of the modal, such as the enter and exit transitions, the duration of the transitions, and modal barrier properties. Additionally, there is a subclass called <a href="https://pub.dev/documentation/animations/latest/animations/FadeScaleTransitionConfiguration-class.html">FadeScaleTransitionConfiguration</a> which applies the standard values from the new Material Design <a href="https://material.io/design/motion/the-motion-system.html#fade">Fade</a> transition. Here is an example of how to use it in conjunction with the <a href="https://pub.dev/documentation/animations/latest/animations/showModal.html">showModal()</a> method:</p><pre><strong>showModal</strong>(<br>  context: context,<br>  configuration: <strong>FadeScaleTransitionConfiguration</strong>(),<br>  builder: (BuildContext context) {<br>   return MyWidget();<br>  },<br>);</pre><h4>A note about Hero widgets</h4><p>The <a href="https://api.flutter.dev/flutter/widgets/Hero-class.html">Hero</a> widget can be used to create a pleasant visual effect when transitioning between routes in a <a href="https://pub.dev/documentation/animations/latest/animations/showModal.html">Navigator</a>. A <a href="https://api.flutter.dev/flutter/widgets/Hero-class.html">Hero</a> widget appears to from its original location in the old route to its final location in the new route. However, in our testing, <a href="https://api.flutter.dev/flutter/widgets/Hero-class.html">Hero</a> widgets do not work with the new Material Design transitions when used inside a <a href="https://pub.dev/documentation/animations/latest/animations/OpenContainer-class.html">OpenContainer</a> or a <a href="https://pub.dev/documentation/animations/latest/animations/PageTransitionSwitcher-class.html">PageTransitionSwitcher</a>. However, they <em>do</em> work when using the <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a> subclassing technique shown above.</p><h4>Conclusion</h4><p>The new <a href="https://material.io/design/motion/the-motion-system.html">motion system</a> is an exciting evolution of <a href="https://material.io/">Material Design</a> and reflects the increasing importance of motion effects in modern application design. The new transitions are subtle and communicative without being overbearing. It is fantastic that they have first-class support in Flutter via the <a href="https://pub.dev/packages/animations">animations</a> package. We are especially excited that they can also be used as custom <a href="https://api.flutter.dev/flutter/widgets/PageRoute-class.html">PageRoute</a> implementations. We encourage you to give it a try!</p><p>Disclaimer: The observations above are the result of our quick testing of the new Flutter <a href="https://pub.dev/packages/animations">animations</a> package. Let us know in the comments if you find anything different in your own testing.</p><p><a href="https://medium.com/u/b72624a26452">Kawynfurstoss</a><strong> </strong>and <a href="https://medium.com/u/5fa1e8853b0a">Hashim Hayat</a> contributed to this blog post.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/0*_edcFCBLMYhOa1-X.png" /><figcaption><a href="http://verygood.ventures/">Very Good Ventures</a> is the world’s premier Flutter technology studio. We built the first-ever Flutter app in 2017 and have been on the bleeding edge ever since. We offer a full range of services including consultations, full-stack development, team augmentation, and technical oversight. We are always looking for developers and interns, so <a href="https://angel.co/very-good-ventures/jobs">drop us a line</a>! Tell us more about your experience and ambitions with Flutter.</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3e26b10c43c1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/a-deep-dive-into-the-flutter-animations-package-3e26b10c43c1">A Deep Dive into the Flutter Animations package</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing Property Change Notifier]]></title>
            <link>https://medium.com/flutter-nyc/introducing-property-change-notifier-10e6d27080a3?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/10e6d27080a3</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Wed, 04 Sep 2019 15:04:26 GMT</pubDate>
            <atom:updated>2019-12-19T18:05:57.574Z</atom:updated>
            <content:encoded><![CDATA[<p><em>A drop-in replacement for </em><a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html"><em>ChangeNotifier</em></a><em> for observing only certain properties of a model.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*h36AjX4nHxVP1nfVm0n9Uw.jpeg" /></figure><p>If you are a <a href="https://medium.com/flutter-nyc/introducing-property-change-notifier-10e6d27080a3">Flutter</a> developer, chances are you’ve come across <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>. It is an implementation of the <a href="https://en.wikipedia.org/wiki/Observer_pattern">Observer pattern</a> and is used to allow multiple listeners to observe a model for changes. It is easy to understand and implement. Here is an example:</p><pre>class MyModel with <strong>ChangeNotifier</strong> {<br>  int _foo;<br>  int _bar;</pre><pre>  int get foo =&gt; _foo;<br>  int get bar =&gt; _bar;</pre><pre>  set foo(int value) {<br>    _foo = value;<br>    <strong>notifyListeners();</strong><br>  }</pre><pre>  set bar(int value) {<br>    _bar = value;<br>    <strong>notifyListeners();</strong><br>  }<br>}</pre><p>Implementers just need to extend or mix-in <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> and convert any public properties to <a href="https://dev.to/newtonmunene_yg/dart-getters-and-setters-1c8f">getters and setters</a> backed by private fields. Then in each setter, and any mutator methods, call notifyListeners(). Any listeners will then be notified. A listener is a simple <a href="https://api.flutter.dev/flutter/dart-ui/VoidCallback.html">VoidCallback</a> and can be added using the following syntax:</p><pre>final model = MyModel();<br>model.addListener(_listener);</pre><pre>void _listener() {<br>  print(&#39;Model changed!&#39;);<br>}</pre><p>The problem is this is an all-or-none approach. As your class grows in size, even small mutations will trigger model-wide change notifications. If you are using Flutter, that can result in a lot of unnecessary widget rebuilds. You may find yourself working around this by not calling notifyListeners() for some mutations, and it’s a slippery slope from there.</p><p>The problem is that the <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> implementation provides no way to broadcast or listen to specific properties only. To do so would require every property to be implemented as a <a href="https://api.flutter.dev/flutter/foundation/ValueNotifier-class.html">ValueNotifier</a> or similar. The <a href="https://pub.dev/packages/observable">Observable</a> package has some powerful tools but they are not backwards-compatible with <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>.</p><p>That’s why we created <a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a>, a <strong>drop-in replacement</strong> for <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> that implements a more granular observer pattern similar to <a href="https://docs.oracle.com/javase/7/docs/api/java/beans/PropertyChangeListener.html">PropertyChangeListener</a> in Java and <a href="https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged.propertychanged?view=netframework-4.8">INotifyPropertyChanged</a> in .NET. When a property changes, the name of the property is included in the notification. <strong>Listeners can then choose to observe one or more properties only</strong>.</p><p>What do we mean by “drop-in replacement”? It means that <a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a> can be used in place of <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> and existing listeners can continue working without modification. Then you can incrementally migrate the listeners over time. Here’s an example:</p><pre>class MyModel with <strong>PropertyChangeNotifier&lt;String&gt;</strong> {<br>  int _foo;<br>  int _bar;</pre><pre>  int get foo =&gt; _foo;<br>  int get bar =&gt; _bar;</pre><pre>  set foo(int value) {<br>    _foo = value;<br>    <strong>notifyListeners(&#39;foo&#39;);</strong><br>  }</pre><pre>  set bar(int value) {<br>    _bar = value;<br>    <strong>notifyListeners(&#39;bar&#39;);</strong><br>  }<br>}</pre><p>First, update your model to extend or mix-in <a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a>. Notice that it takes an additional generic type parameter. This is the type you wish to use for properties (typically String). Then simply provide the property name as a parameter to notifyListeners().</p><p>As promised, existing listeners will continue to function as expected. The following legacy listener will continue to be invoked on every property change:</p><pre>final model = MyModel();<br>model.addListener(_listener);</pre><pre>void _listener() {<br>  print(&#39;Model changed!&#39;);<br>}</pre><p>However, now we can be more selective with our listeners! <strong>To listen to one or more properties, include them as a parameter to the </strong><strong>addListener() method</strong>. Let’s create a few different kinds of listeners:</p><blockquote>The parameter list can be a <a href="https://api.dartlang.org/stable/2.4.1/dart-core/List-class.html">List</a>, <a href="https://api.dartlang.org/stable/2.4.1/dart-core/Set-class.html">Set</a>, or any <a href="https://api.dartlang.org/stable/2.4.1/dart-core/Iterable-class.html">Iterable</a>.</blockquote><pre>final model = MyModel();<br><strong>model.addListener(_globalListener);<br>model.addListener(_fooListener, [&#39;foo&#39;]);<br>model.addListener(_bothListener, [&#39;foo&#39;, &#39;bar&#39;]);</strong></pre><pre>void _globalListener() {<br>  print(&#39;Model changed!&#39;);<br>}</pre><pre>void _fooListener() {<br>  print(&#39;Foo changed!&#39;);<br>}</pre><pre>void _bothListener() {<br>  print(&#39;Foo or bar changed!&#39;);<br>}</pre><p><strong>To know what specific property changed, a listener can optionally accept a property parameter.</strong> This applies to global listeners as well.</p><pre>final model = MyModel();<br>model.addListener(_globalListener);<br>model.addListener(_bothListener, [&#39;foo&#39;, &#39;bar&#39;]);</pre><pre>void _globalListener(<strong>String property</strong>) {<br>  print(&#39;$property changed!&#39;);<br>}</pre><pre>void _bothListener(<strong>String property</strong>) {<br>  print(&#39;$property changed!&#39;);<br>}</pre><h4>Property names</h4><p>Referring to properties using <a href="https://api.dartlang.org/stable/2.4.1/dart-core/String-class.html">string literals</a> is error-prone and leads to <a href="https://www.techopedia.com/definition/31876/stringly-typed">stringly-typed</a> code. To avoid this, you can reference string constants in both your model and listeners so that they can be safely checked by the compiler:</p><pre>// Properties<br><strong>abstract class MyModelProperties {<br>  static String get foo =&gt; &#39;foo&#39;;<br>  static String get bar =&gt; &#39;bar&#39;;<br>}</strong></pre><pre>// Model<br>class MyModel extends PropertyChangeNotifier {<br>  set foo(int value) {<br>    _foo = value;<br>    notifyListeners(<strong>MyModelProperties.foo</strong>);<br>  }<br>  …<br>}</pre><pre>// Listener<br>final model = MyModel();<br>model.addListener(_listener, [<strong>MyModelProperties.foo</strong>]);</pre><blockquote>You can even use an <em>Enum</em>, or any type that extends <em>Object</em> and correctly implements equality using <em>==</em> and <em>hashCode</em>.</blockquote><p><a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a> provides the ease and simplicity of <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>, but with the added granularity needed for more efficient change notifications! 👏</p><h3>Usage with Widgets</h3><p>How do we use <a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a> with Widgets? Inspired by the <a href="https://pub.dev/packages/provider">Provider</a> package, we created a widget called <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeProvider-class.html">PropertyChangeProvider</a> that uses <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> under the hood. First, create a <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeProvider-class.html">PropertyChangeProvider</a> widget with an instance of your model:</p><pre>PropertyChangeProvider(<br>  value: MyModel(),<br>  child: MyApp(...)<br>};</pre><blockquote>The model instance can come from anywhere, including <a href="https://pub.dev/packages/provider">Provider</a> or a regular state variable in a <a href="https://api.flutter.dev/flutter/widgets/State-class.html">StatefulWidget</a>.</blockquote><p>Then, from any descendant widget, listen for changes to all or some properties by using the standard of() syntax. You can then access both the model itself and the properties that were changed in the current build frame. Here are a few different examples:</p><pre>// Rebuilds when any property changes<br>class GlobalListener extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    <strong>PropertyChangeProvider.of&lt;MyModel&gt;(context);</strong><br>    return Text(&#39;MyModel changed!);<br>  }<br>}</pre><pre>// Rebuilds when foo changes<br>class FooListener extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br><strong>    final model = PropertyChangeProvider.of&lt;MyModel&gt;(context, properties: [&#39;foo&#39;]).value;    <br></strong>    return Text(&#39;Foo changed to ${model.foo}&#39;);<br>  }<br>}</pre><pre>// Rebuilds when foo or bar changes<br>class BothListener extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    <strong>final properties = PropertyChangeProvider.of&lt;MyModel&gt;(context, properties: [&#39;foo&#39;, &#39;bar&#39;]).properties;</strong><br>    return Text(&#39;$properties changed&#39;);<br>  }<br>}</pre><blockquote>Note: properties will be empty on the initial build, because the model has not changed yet. Be sure to handle this case.</blockquote><h4>Listening without rebuilding</h4><p>By simply calling the of() method from a widget’s build() method, that widget is automatically registered to rebuild on model changes. To access a model <em>without</em> registering for a rebuild, add a listen parameter with a value of false. In this example below, RaisedButton does not depend on the value of foo and so does not need to be rebuilt if it changes.</p><pre>// Will not be rebuilt when model changes<br>class NotListener extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    final model = PropertyChangeProvider.of&lt;MyModel&gt;(context, <strong>listen: false</strong>).value;<br>    return RaisedButton(<br>      child: Text(&#39;Update foo&#39;),<br>      onPressed = () =&gt; model.foo++<br>    };<br>  }<br>}</pre><h4>Consumer widget</h4><p>We also created <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeConsumer-class.html">PropertyChangeConsumer</a>, a widget-based listener for cases where a <a href="https://api.flutter.dev/flutter/widgets/BuildContext-class.html">BuildContext</a> is hard to access, or if you prefer this kind of API. You can access both the model value and the changed properties via the builder callback:</p><pre>class ConsumerListener extends StatelessWidget {<br>  @<em>override</em><br>  Widget build(BuildContext context) {<br>    return <strong>PropertyChangeConsumer&lt;MyModel&gt;(<br>      properties: [&#39;foo&#39;, &#39;bar&#39;],<br>      builder: (context, model, properties)</strong> {<br>        return Column(<br>          children: [<br>            Text(&#39;$properties changed!&#39;),<br>            RaisedButton(<br>              child: Text(&#39;Update foo&#39;),<br>              onPressed: () =&gt; model.foo++,<br>            ),<br>            RaisedButton(<br>              child: Text(&#39;Update bar&#39;),<br>              onPressed: () =&gt; model.bar++,<br>            ),<br>          ],<br>        );<br>      },<br>    );<br>  }<br>}</pre><h3>Implementation Details</h3><p><a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeNotifier-class.html">PropertyChangeNotifier</a> was relatively straightforward to implement. It replicates much of the behavior of <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a>, but instead of storing listeners in a single <a href="https://api.flutter.dev/flutter/dart-core/List-class.html">List</a>, it stores them in a <a href="https://api.flutter.dev/flutter/dart-core/Map-class.html">Map</a> where the key is the property name and the value is a <a href="https://api.flutter.dev/flutter/dart-core/List-class.html">List</a> of listeners. The way that listeners are invoked in <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> is interesting (and we replicated it). While looping through the list and invoking listeners, there is the risk that a listener might itself add or remove other listeners. This would mutate the list while iterating through it, which would throw an exception. So first the list is copied before being iterated. But there is still the risk that a listener will be removed after making the copy. So, before invoking each listener, we check to see if it is still contained in the original list. To make this process more efficient, <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> uses a special <a href="https://api.flutter.dev/flutter/dart-core/List-class.html">List</a> subclass called <a href="https://api.flutter.dev/flutter/foundation/ObserverList-class.html">ObserverList</a>, which uses a backing <a href="https://api.dartlang.org/stable/dart-collection/HashSet-class.html">HashSet</a> to determine whether it contains a given item.</p><p>The implementation of <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeProvider-class.html">PropertyChangeProvider</a> was more interesting. We used <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> because it allows us to register a descendant widget to be rebuilt if needed. This is typically done by calling context.inheritFromWidgetOfExactType(). However this gives us no mechanism for limiting rebuilds to only certain properties of <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeNotifier-class.html">PropertyChangeNotifier</a>. Fortunately, we can use <a href="https://api.flutter.dev/flutter/widgets/InheritedModel-class.html">InheritedModel</a> instead. <a href="https://api.flutter.dev/flutter/widgets/InheritedModel-class.html">InheritedModel</a> is a subclass of <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> that lets a descendant widget subscribe to certain <em>aspects</em> of a model by callingInheritedModel.inheritFrom(context, aspect: aspect). In our <a href="https://api.flutter.dev/flutter/widgets/InheritedModel-class.html">InheritedModel</a> subclass, we check each dependent widgets’ aspect list against the current changed properties set to determine if it should be rebuilt. This implementation has the added benefit of being efficient. For every <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeProvider-class.html">PropertyChangeProvider</a>, there is only one model listener — the provider itself. So no need to worry about the performance implications of adding many descendant widgets listening to that provider.</p><h3>Tests</h3><p>A library that is as foundational as <a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a> must be tested thoroughly, and we are happy to announce that it currently has <a href="http://htmlpreview.github.io/?https://github.com/vgventures/property_change_notifier/blob/master/coverage/html/index.html">100% test coverage</a>. There are roughly twice as many LOC in the unit tests as there are in the implementation! So you can feel confident using it. Of course, if we missed anything, <a href="https://github.com/vgventures/property_change_notifier/issues">let us know</a>!</p><p>We hope you find <a href="https://pub.dev/packages/property_change_notifier">PropertyChangeNotifier</a> as useful as we have! Feel free to file an issue or feature request. One known issue is the lack of generic type safety of the <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeConsumer/properties.html">properties</a> parameter in both <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeProvider-class.html">PropertyChangeProvider</a> and <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeConsumer-class.html">PropertyChangeConsumer</a>. This could be solved by passing an additional generic type to the of() method, but we think this muddies up the API a bit. Also, strongly typing the <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeModel/property.html">properties</a> Set type of <a href="https://pub.dev/documentation/property_change_notifier/latest/property_change_notifier/PropertyChangeModel-class.html">PropertyChangeModel</a> is tricky because it seems to break InheritedModel.inheritFrom(). Any <a href="https://github.com/vgventures/property_change_notifier/issues">suggestions or contributions</a> are welcome!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/0*tGAk6IBEs_XwghFF.png" /><figcaption><a href="http://verygood.ventures/">Very Good Ventures</a> is the world’s premier Flutter technology studio. We built the first-ever Flutter app in 2017 and have been on the bleeding edge ever since. We offer a full range of services including consultations, full-stack development, team augmentation, and technical oversight. We are always looking for developers and interns, so <a href="https://angel.co/very-good-ventures/jobs">drop us a line</a>! Tell us more about your experience and ambitions with Flutter.</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=10e6d27080a3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/introducing-property-change-notifier-10e6d27080a3">Introducing Property Change Notifier</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Closer Look at the Provider Package]]></title>
            <link>https://medium.com/flutter-nyc/a-closer-look-at-the-provider-package-993922d3a5a5?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/993922d3a5a5</guid>
            <category><![CDATA[provider]]></category>
            <category><![CDATA[bloc]]></category>
            <category><![CDATA[state-management]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Tue, 30 Jul 2019 14:37:46 GMT</pubDate>
            <atom:updated>2019-08-19T16:56:41.273Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Plus a Brief History of State Management in Flutter</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Ah2h28bxT0-vk18Q4xVVA.jpeg" /></figure><p><a href="https://pub.dev/packages/provider">Provider</a> is a state management package written by <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjXrMKO8dLjAhWoT98KHUCDB_oQFjAAegQIARAB&amp;url=https%3A%2F%2Ftwitter.com%2Fremi_rousselet&amp;usg=AOvVaw3bEIgT0j4c_5xbq-YWB70q">Remi Rousselet</a> that has been recently embraced by Google and the Flutter community. But what <em>is</em> state management? Heck, what is <em>state</em>? Recall that state is simply the data that represents the UI in our app. <em>State management</em> is how we create, access, update, and dispose this data. To better understand the Provider package, let’s look at a brief history of state management options in Flutter.</p><h3>1. StatefulWidget</h3><p>A <a href="https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html">StatelessWidget</a> is a simple UI component that displays only the data it is given. A StatelessWidget has no “memory”; it is created and destroyed as needed. Flutter also comes with a <a href="https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html">StatefulWidget</a> that <em>does</em> have a memory thanks to its long-lived companion <a href="https://api.flutter.dev/flutter/widgets/State-class.html">State</a> object. This class comes with a setState() method that, when invoked, triggers the widget to rebuild and display the new state. This is the most basic, out-of-the-box form of state management in Flutter. Here is an example with a button that always shows the last time it was tapped:</p><pre>class _MyWidgetState extends State&lt;MyWidget&gt; {<br>  DateTime _time = DateTime.now();</pre><pre>  @override<br>  Widget build(BuildContext context) {<br>    return FlatButton(<br>      child: Text(_time.toString()),<br>      onPressed: () {<br>        setState(() =&gt; _time = DateTime.now());<br>      },<br>    );<br>  }<br>}</pre><p>So what’s the problem with this approach? Let’s say that our app has some global state stored in a root <a href="https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html">StatefulWidget</a>. It contains data that is intended to be used by many different parts of the UI. We share that data by passing it down to every child widget in the form of parameters. And any events that intend to mutate this data are bubbled back up in the form of callbacks. This means a lot of parameters and callbacks being passed through many intermediate widgets, which can get very messy. Even worse, any updates to that root state will trigger a rebuild of the whole widget tree, which is inefficient.</p><h3>2. InheritedWidget</h3><p><a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> is a special kind of widget that lets its descendants access it without having a direct reference. By simply accessing an <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a>, a consuming widget can register to be automatically rebuilt whenever the inherited widget is rebuilt. This technique lets us be more efficient when updating our UI. Instead of rebuilding huge parts of our app in response to a small state change, we can surgically choose to rebuild only specific widgets. You’ve already used <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> whenever you’ve used MediaQuery.of(context) or Theme.of(context). It’s probably less likely that you’ve ever implemented your own stateful <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> though. That’s because they are <a href="https://flutterbyexample.com/set-up-inherited-widget-app-state/">tricky to implement</a> correctly.</p><h3>3. ScopedModel</h3><p><a href="https://pub.dev/packages/scoped_model">ScopedModel</a> is a package created in 2017 by <a href="https://twitter.com/brianegan">Brian Egan</a> that makes it easier to use an <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a> to store app state. First we have to make a state object that inherits from <a href="https://pub.dev/documentation/scoped_model/latest/scoped_model/Model-class.html">Model</a>, and then invoke notifyListeners() when its properties change. This is similar to implementing the <a href="https://docs.oracle.com/javase/7/docs/api/java/beans/PropertyChangeListener.html">PropertyChangeListener</a> interface in Java.</p><pre>class MyModel extends Model {<br>  String _foo;</pre><pre>  String get foo =&gt; _foo;<br>  <br>  void set foo(String value) {<br>    _foo = value;<br>    notifyListeners();  <br>  }<br>}</pre><p>To expose our state object, we wrap our state object instance in a <a href="https://pub.dev/documentation/scoped_model/latest/scoped_model/ScopedModel-class.html">ScopedModel</a> widget at the root of our app:</p><pre>ScopedModel&lt;MyModel&gt;(<br>  model: MyModel(),<br>  child: MyApp(...)<br>)</pre><p>Any descendant widget can now access MyModel by using the <a href="https://pub.dev/documentation/scoped_model/latest/scoped_model/ScopedModelDescendant-class.html">ScopedModelDescendant</a> widget. The model instance is passed into the builder parameter:</p><pre>class MyWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    return ScopedModelDescendant&lt;MyModel&gt;(<br>      builder: (context, child, model) =&gt; Text(model.foo),<br>    );<br>  }<br>}</pre><p>Any descendant widget can also <em>update</em> the model, and it will automatically trigger a rebuild of any ScopedModelDescendants (provided that our model invokes notifyListeners() correctly):</p><pre>class OtherWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    return FlatButton(<br>      child: Text(&#39;Update&#39;),<br>      onPressed: () {<br>        final model = ScopedModel.of&lt;MyModel&gt;(context);<br>        model.foo = &#39;bar&#39;;<br>      },<br>    );<br>  }<br>}</pre><p><a href="https://pub.dev/packages/scoped_model">ScopedModel</a> became a popular form of state management in Flutter, but is limited to exposing state objects that extend the <a href="https://pub.dev/documentation/scoped_model/latest/scoped_model/Model-class.html">Model</a> class and its change notifier pattern.</p><h3>4. BLoC</h3><p>At <a href="https://www.youtube.com/watch?v=RS36gBEp8OI">Google I/O ’18</a>, the <a href="https://www.freecodecamp.org/news/how-to-handle-state-in-flutter-using-the-bloc-pattern-8ed2f1e49a13/">Business Logic Component</a> (BLoC) pattern was introduced as another pattern for moving state out of widgets. BLoC classes are long-lived, non-UI components that hold onto state and expose it in the form of <a href="http://dart stream listen">streams</a> and <a href="https://api.dartlang.org/stable/2.4.0/dart-core/Sink-class.html">sinks</a>. By moving state and business logic out of the UI, it allows a widget to be implemented as a simple <a href="https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html">StatelessWidget</a> and use a <a href="https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html">StreamBuilder</a> to automatically rebuild. This makes the widget “dumber” and easier to test.</p><p>An example of a BLoC class:</p><pre>class MyBloc {<br>  final _controller = StreamController&lt;MyType&gt;();</pre><pre>  Stream&lt;MyType&gt; get stream =&gt; _controller.stream;<br>  StreamSink&lt;MyType&gt; get sink =&gt; _controller.sink;<br>  <br>  myMethod() {<br>    // YOUR CODE<br>    sink.add(foo);<br>  }</pre><pre>  dispose() {<br>    _controller.close();<br>  }<br>}</pre><p>An example of a widget consuming a BLoC:</p><pre>@override<br>Widget build(BuildContext context) {<br> return StreamBuilder&lt;MyType&gt;(<br>  stream: myBloc.stream,<br>  builder: (context, asyncSnapshot) {<br>    // YOUR CODE<br> });<br>}</pre><p>The trouble with the BLoC pattern is that it is not obvious how to create and destroy BLoC objects. In the example above, how was the myBloc instance created? How do we call dispose() on it? <a href="http://dart stream listen">Streams</a> require the use of a <a href="https://api.dartlang.org/stable/2.4.0/dart-async/StreamController-class.html">StreamController</a>, which must be closed when no longer needed in order to prevent memory leaks. (Dart has no notion of a class <a href="https://en.wikipedia.org/wiki/Destructor_(computer_programming)">destructor</a>; only the StatefulWidget <a href="https://api.flutter.dev/flutter/widgets/State-class.html">State</a> class has a dispose() method.) Also, it is not clear how to share this BLoC across multiple widgets. So it is often difficult for developers to get started using BLoC. There are some <a href="https://pub.dev/flutter/packages?q=bloc">packages</a> that attempt to make this easier.</p><h3>5. Provider</h3><p><a href="https://pub.dev/packages/provider">Provider</a> is a package written in 2018 by <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjXrMKO8dLjAhWoT98KHUCDB_oQFjAAegQIARAB&amp;url=https%3A%2F%2Ftwitter.com%2Fremi_rousselet&amp;usg=AOvVaw3bEIgT0j4c_5xbq-YWB70q">Remi Rousselet</a> that is similar to <a href="https://pub.dev/packages/scoped_model">ScopedModel</a> but is not limited to exposing a <a href="https://pub.dev/documentation/scoped_model/latest/scoped_model/Model-class.html">Model</a> subclass. It too is a wrapper around <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a>, but can expose any kind of state object, including BLoC, <a href="http://dart stream listen">streams</a>, <a href="https://api.dartlang.org/stable/dart-async/Future-class.html">futures</a>, and others. Because of its simplicity and flexibility, Google announced at <a href="https://www.youtube.com/watch?v=d_m5csmrf7I">Google I/O </a>’19 that <a href="https://pub.dev/packages/provider">Provider</a> is now its preferred package for state management. Of course, you can still use <a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt/options">others</a>, but if you’re not sure what to use, Google recommends going with <a href="https://pub.dev/packages/provider">Provider</a>.</p><p><a href="https://pub.dev/packages/provider">Provider</a> is built “with widgets, for widgets.” With <a href="https://pub.dev/packages/provider">Provider</a>, we can place any state object into the widget tree and make it accessible from any other (descendant) widget. <a href="https://pub.dev/packages/provider">Provider</a> also helps manage the lifetime of state objects by initializing them with data and cleaning up after them when they are removed from the widget tree. For this reason, <a href="https://pub.dev/packages/provider">Provider</a> can even be used to implement BLoC components, or serve as the basis for <a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt/options">other</a> state management solutions! 😲 Or it can be used simply for <a href="https://en.wikipedia.org/wiki/Dependency_injection">dependency injection</a> — a fancy term for passing data into widgets in a way that reduces coupling and increases testability. Finally, <a href="https://pub.dev/packages/provider">Provider</a> comes with a set of specialized classes that make it even more user-friendly. We’ll explore each of these in detail.</p><ul><li>Basic <a href="https://pub.dev/documentation/provider/latest/provider/Provider-class.html">Provider</a></li><li><a href="https://pub.dev/documentation/provider/latest/provider/ChangeNotifierProvider-class.html">ChangeNotifierProvider</a></li><li><a href="https://pub.dev/documentation/provider/latest/provider/StreamProvider-class.html">StreamProvider</a></li><li><a href="https://pub.dev/documentation/provider/latest/provider/FutureProvider-class.html">FutureProvider</a></li><li><a href="http://valuelistenableprovider/">ValueListenableProvider</a></li><li><a href="https://pub.dev/documentation/provider/latest/provider/MultiProvider-class.html">MultiProvider</a></li><li><a href="https://pub.dev/documentation/provider/latest/provider/ProxyProvider-class.html">ProxyProvider</a></li></ul><h4>Installing</h4><p>First, to use <a href="https://pub.dev/packages/provider">Provider</a>, add the dependency to your pubspec.yaml:</p><pre>provider: ^3.0.0</pre><p>Then import the <a href="https://pub.dev/packages/provider">Provider</a> package where needed:</p><pre>import &#39;package:provider/provider.dart&#39;;</pre><h4>Basic Provider</h4><p>Let’s create a basic <a href="https://pub.dev/packages/provider">Provider</a> at the root of our app containing an instance of our model:</p><pre>Provider&lt;MyModel&gt;(<br>  builder: (context) =&gt; MyModel(),<br>  child: MyApp(...),<br>)</pre><blockquote>The builder parameter creates instance of MyModel. If you want to give it an existing instance, use the <a href="https://pub.dev/documentation/provider/latest/provider/Provider/Provider.value.html">Provider.value</a> constructor instead.</blockquote><p>We can then <em>consume</em> this model instance anywhere in MyAppby using the <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> widget:</p><pre>class MyWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    return Consumer&lt;MyModel&gt;(<br>      builder: (context, value, child) =&gt; Text(value.foo),<br>    );<br>  }<br>}</pre><p>In the example above, the MyWidget class obtains the MyModel instance using the <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> widget. This widget gives us a builder containing our object in the value parameter.</p><p>Now, what if we want to <em>update</em> the data in our model? Let’s say that we have another widget where pushing a button should update the foo property:</p><pre>class OtherWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    return FlatButton(<br>      child: Text(&#39;Update&#39;),<br>      onPressed: () {<br>        final model = Provider.of&lt;MyModel&gt;(context);<br>        model.foo = &#39;bar&#39;;<br>      },<br>    );<br>  }<br>}</pre><blockquote>Note the different syntax for accessing our MyModel instance. This is functionally equivalent to using the <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> widget. The <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> widget is useful if you can’t easily get a <a href="https://api.flutter.dev/flutter/widgets/BuildContext-class.html">BuildContext</a> reference in your code.</blockquote><p>What do you expect will happen to the original MyWidget we created earlier? Do you think it will now display the new value of bar? <strong>Unfortunately, no</strong>. It is not possible to listen to changes on plain old Dart objects (at least not without <a href="https://api.dartlang.org/stable/dart-mirrors/dart-mirrors-library.html">reflection</a>, which is not available in Flutter). That means <a href="https://pub.dev/packages/provider">Provider</a> is not able to “see” that we updated the foo property and tell MyWidget to update in response.</p><h4>ChangeNotifierProvider</h4><p>However, there is hope! We can make our MyModel class implement the <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html">ChangeNotifier</a> mixin. We need to modify our model implementation slightly by invoking a special notifyListeners() method whenever one of our properties change. This is similar to how <a href="https://pub.dev/packages/scoped_model">ScopedModel</a> works, but it’s nice that we don’t need to inherit from a particular model class. We can just implement the <a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-%E2%80%A6">ChangeNotifier</a> mixin. Here’s what that looks like:</p><pre>class MyModel with ChangeNotifier {<br>  String _foo;</pre><pre>  String get foo =&gt; _foo;<br>  <br>  void set foo(String value) {<br>    _foo = value;<br>    notifyListeners();  <br>  }<br>}</pre><p>As you can see, we changed our foo property into a getter and setter backed by a private _foo variable. This allows us to “intercept” any changes made to the foo property and tell our listeners that our object changed.</p><p>Now, on the <a href="https://pub.dev/packages/provider">Provider</a> side, we can change our implementation to use a different class called <a href="https://pub.dev/documentation/provider/latest/provider/ChangeNotifierProvider-class.html">ChangeNotifierProvider</a>:</p><pre>ChangeNotifierProvider&lt;MyModel&gt;(<br>  builder: (context) =&gt; MyModel(),<br>  child: MyApp(...),<br>)</pre><p>That’s it! Now when our OtherWidget updates the foo property on our MyModel instance, MyWidget will automatically update to reflect that change. Cool huh?</p><p>One more thing. You may have noticed in the OtherWidget button handler that we used the following syntax:</p><pre>final model = Provider.of&lt;MyModel&gt;(context);</pre><p><strong>By default, this syntax will automatically cause our </strong><strong>OtherWidget instance to rebuild whenever </strong><strong>MyModel changes.</strong> That might not be what we want. After all, OtherWidget just contains a button that doesn’t change based on the value of MyModel at all. To avoid this, we can use the following syntax to access our model <em>without</em> registering for a rebuild:</p><pre>final model = Provider.of&lt;MyModel&gt;(context, listen: false);</pre><p>This is another nicety that the <a href="https://pub.dev/packages/provider">Provider</a> package gives us for free.</p><h4>StreamProvider</h4><p>At first glance, the <a href="https://pub.dev/documentation/provider/latest/provider/StreamProvider-class.html">StreamProvider</a> seems unnecessary. After all, we can just use a regular <a href="https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html">StreamBuilder</a> to consume a stream in Flutter. For example, here we listen to the <a href="https://pub.dev/documentation/firebase_auth/latest/firebase_auth/FirebaseAuth/onAuthStateChanged.html">onAuthStateChanged</a> stream provided by <a href="https://pub.dev/documentation/firebase_auth/latest/firebase_auth/firebase_auth-library.html">FirebaseAuth</a>:</p><pre>@override<br>Widget build(BuildContext context {<br>  return StreamBuilder(<br>   stream: FirebaseAuth.instance.onAuthStateChanged, <br>   builder: (BuildContext context, AsyncSnapshot snapshot){ <br>     ...<br>   });<br>}</pre><p>To do this with <a href="https://pub.dev/packages/provider">Provider</a> instead, we can expose this stream via a <a href="https://pub.dev/documentation/provider/latest/provider/StreamProvider-class.html">StreamProvider</a> at the root of our app:</p><pre>StreamProvider&lt;FirebaseUser&gt;.value(<br>  stream: FirebaseAuth.instance.onAuthStateChanged,<br>  child: MyApp(...),<br>}</pre><p>Then consume it in a child widget like any other <a href="https://pub.dev/packages/provider">Provider</a>:</p><pre>@override<br>Widget build(BuildContext context) {<br>  return Consumer&lt;FirebaseUser&gt;(<br>    builder: (context, value, child) =&gt; Text(value.displayName),<br>  );<br>}</pre><p>Besides making the consuming widget code much cleaner, <strong>it also abstracts away the fact that the data is coming from a stream</strong>. If we ever decide to change the underlying implementation to a <a href="https://pub.dev/documentation/provider/latest/provider/FutureProvider-class.html">FutureProvider</a>, for instance, it will require no changes to our widget code. <em>In fact, you’ll see that this is the case for all of the different providers below</em>. 😲</p><h4>FutureProvider</h4><p>Similar to the example above, <a href="https://pub.dev/documentation/provider/latest/provider/FutureProvider-class.html">FutureProvider</a> is an alternative to using the standard <a href="https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html">FutureBuilder</a> inside our widgets. Here is an example:</p><pre>FutureProvider&lt;FirebaseUser&gt;.value(<br>  value: FirebaseAuth.instance.currentUser(),<br>  child: MyApp(...),<br>);</pre><p>To consume this value in a child widget, we use the same <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> implementation used in the <a href="https://pub.dev/documentation/provider/latest/provider/StreamProvider-class.html">StreamProvider</a> example above.</p><h4>ValueListenableProvider</h4><p><a href="https://api.flutter.dev/flutter/foundation/ValueListenable-class.html">ValueListenable</a> is a Dart interface implemented by the <a href="https://api.flutter.dev/flutter/foundation/ValueNotifier-class.html">ValueNotifier</a> class that takes a value and notifies listeners when it changes to another value. We can use it to wrap an integer counter in a simple model class:</p><pre>class MyModel {<br>  final ValueNotifier&lt;int&gt; counter = ValueNotifier(0);  <br>}</pre><blockquote>When using complex types, <a href="https://api.flutter.dev/flutter/foundation/ValueNotifier-class.html">ValueNotifier</a> uses the <em>==</em> operator of the contained object to determine whether the value has changed.</blockquote><p>Let’s create a basic <a href="https://pub.dev/packages/provider">Provider</a> to hold our main model, followed by a <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> and a nested <a href="https://pub.dev/documentation/provider/latest/provider/ValueListenableProvider-class.html">ValueListenableProvider</a> that listens to the counter property:</p><pre>Provider&lt;MyModel&gt;(<br>  builder: (context) =&gt; MyModel(),<br>  child: Consumer&lt;MyModel&gt;(builder: (context, value, child) {<br>    return ValueListenableProvider&lt;int&gt;.value(<br>      value: value.counter,<br>      child: MyApp(...)<br>    }<br>  }<br>}</pre><blockquote>Note that the type of the nested provider is int. You might have others. If you have multiple Providers registered for the same type, <a href="https://pub.dev/packages/provider">Provider</a> will return the “closest” one (nearest ancestor).</blockquote><p>Here’s how we can listen to the counter property from any descendant widget:</p><pre>class MyWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    return Consumer&lt;int&gt;(<br>      builder: (context, value, child) {<br>        return Text(value.toString());<br>      },<br>    );<br>  }<br>}</pre><p>And here is how we can <em>update</em> the counter property from yet another widget. Note that we need to access the original MyModel instance.</p><pre>class OtherWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    return FlatButton(<br>      child: Text(&#39;Update&#39;),<br>      onPressed: () {<br>        final model = Provider.of&lt;MyModel&gt;(context);<br>        model.counter.value++;<br>      },<br>    );<br>  }<br>}</pre><h4>MultiProvider</h4><p>If we are using many <a href="https://pub.dev/packages/provider">Provider</a> widgets, we may end up with an ugly nested structure at the root of our app:</p><pre>Provider&lt;Foo&gt;.value( <br>  value: foo, <br>  child: Provider&lt;Bar&gt;.value( <br>    value: bar, <br>    child: Provider&lt;Baz&gt;.value( <br>      value: baz , <br>      child: MyApp(...)<br>    ) <br>  ) <br>)</pre><p><a href="https://pub.dev/documentation/provider/latest/provider/MultiProvider-class.html">MultiProvider</a> lets us declare them all our providers at the same level. This is just <a href="https://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar</a>; they are still being nested behind the scenes.</p><pre>MultiProvider( <br>  providers: [ <br>    Provider&lt;Foo&gt;.value(value: foo), <br>    Provider&lt;Bar&gt;.value(value: bar), <br>    Provider&lt;Baz&gt;.value(value: baz), <br>  ], <br>  child: MyApp(...), <br>)</pre><h4>ProxyProvider</h4><p><a href="https://pub.dev/documentation/provider/latest/provider/ProxyProvider-class.html">ProxyProvider</a> is an interesting class that was added in the v3 release of the <a href="https://pub.dev/packages/provider">Provider</a> package. This lets us declare Providers that themselves are dependent on up to 6 other Providers. In this example, the Bar class depends on an instance of Foo. This is useful when establishing a root set of services that themselves have dependencies on one another.</p><pre>MultiProvider ( <br>  providers: [ <br>    Provider&lt;Foo&gt; ( <br>      builder: (context) =&gt; Foo(),<br>    ), <br>    ProxyProvider&lt;Foo, Bar&gt;(<br>      builder: (context, value, previous) =&gt; Bar(value),<br>    ), <br>  ], <br>  child: MyApp(...),<br>)</pre><blockquote>The first generic type argument is the type your <a href="https://pub.dev/documentation/provider/latest/provider/ProxyProvider-class.html">ProxyProvider</a> depends on, and the second is the type it returns.</blockquote><h4>Listening to Multiple Providers Simultaneously</h4><p>What if we want a single widget to list to multiple Providers, and trigger a rebuild whenever any of them change? We can listen to up to 6 Providers at a time using variants of the <a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html">Consumer</a> widget. We will receive the instances as additional parameters in the builder method.</p><pre>Consumer2&lt;MyModel, int&gt;(<br>  builder: (context, value, value2, child) {<br>    //value is MyModel<br>    //value2 is int<br>  },<br>);</pre><h4>Conclusion</h4><p>By embracing <a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html">InheritedWidget</a>, <a href="https://pub.dev/packages/provider">Provider</a> gives us a “Fluttery” way of state management. It lets widgets access and listen to state objects in a way that abstracts away the underlying notification mechanism. It helps us manage the lifetimes of state objects by providing hooks to create and dispose them as needed. It can be used for simple dependency injection, or even as the basis for more extensive state management options. Having received Google’s blessing, and with growing support from the Flutter community, it is a safe choice to go with. Give <a href="https://pub.dev/packages/provider">Provider</a> a try today!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*nZdqzH6_6qElAb-5AuAtAg.png" /><figcaption><a href="http://verygood.ventures/">Very Good Ventures</a> is the world’s premier Flutter technology studio. We built the first-ever Flutter app in 2017 and have been on the bleeding edge ever since. We offer a full range of services including consultations, full-stack development, team augmentation, and technical oversight. We are always looking for developers and interns, so <a href="https://angel.co/very-good-ventures/jobs">drop us a line</a>! Tell us more about your experience and ambitions with Flutter.</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=993922d3a5a5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/a-closer-look-at-the-provider-package-993922d3a5a5">A Closer Look at the Provider Package</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What SwiftUI Means for Flutter]]></title>
            <link>https://medium.com/flutter-nyc/what-swiftui-means-for-flutter-6d5898f7adf7?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/6d5898f7adf7</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Tue, 04 Jun 2019 16:36:33 GMT</pubDate>
            <atom:updated>2019-06-24T14:17:25.748Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/982/1*eoyNjigMK4j9snBX_MV3tw.png" /></figure><blockquote><strong>TL;DR:</strong> Flutter is likely to benefit as Apple developers see that they can use the same declarative UI techniques as SwiftUI but also run their code on many more platforms, including Android, Windows, Web, and IOT.</blockquote><p><em>This article was originally published on the </em><a href="https://verygood.ventures/blog/2019/6/4/what-swiftui-means-fornbspflutter"><em>Very Good Ventures blog</em></a><em>.</em></p><p>On June 3 at <a href="https://developer.apple.com/wwdc19/">WWDC ’19</a> Apple made a lot of big announcements, but an important one that didn’t quite make the top news headlines was the release of <a href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>, a new <a href="https://flutter.dev/docs/get-started/flutter-for/declarative">declarative UI</a> framework for building <a href="http://developer.apple.com/ios">iOS</a> (and <a href="https://www.apple.com/ipados">iPadOS</a>/<a href="http://developer.apple.com/macos">macOS</a>/<a href="http://developer.apple.com/watchos">watchOS</a>/<a href="http://developer.apple.com/tvos">tvOS</a>) apps. Of course, for software developers this was probably the most exciting news of all. After all, how many of us can actually afford the new <a href="https://www.theverge.com/2019/6/3/18651071/mac-pro-design-specs-hands-on-photos-video-price">Mac Pro</a>?</p><p>The reason why developers are so excited is that Apple has finally joined the modern era of <a href="https://flutter.dev/docs/get-started/flutter-for/declarative">declarative UI programming</a>. Apple developers had to sit on the sidelines as the likes of <a href="http://www.reactnative.com/">React Native</a> and <a href="http://flutter.dev/">Flutter</a> showed off their ability to drastically improve code simplicity and reduce development times with <a href="https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading">hot reloading</a>. Apple developers also sighed as Google announced <a href="https://developer.android.com/jetpack/compose">Jetpack Compose</a>, a new declarative UI framework for Android, at <a href="https://events.google.com/io/">I/O ’19</a>. So when Apple made the <a href="https://developer.apple.com/videos/play/wwdc2019/103/">SwiftUI</a> announcement it was rightly met with collective gasps and cheers in the audience.</p><p>What we are witnessing is a continuation of the declarative UI programming revolution that was popularized by <a href="https://reactjs.org/">React</a>. Thanks Facebook! That needs to be recognized and applauded. <a href="http://flutter.dev/">Flutter</a> also deserves credit for getting us to this point. Flutter is one of the <a href="https://github.com/search?q=stars%3A%3E0&amp;s=stars&amp;type=Repositories">top 10 most-starred repos</a> on Github, was recently ranked the <a href="https://insights.stackoverflow.com/survey/2019#technology">#3 most loved framework</a> in the 2019 Stack Overflow developer survey, and is the <a href="https://learning.linkedin.com/blog/tech-tips/the-fastest-growing-skills-among-software-engineers--and-how-to-">#1 fastest-growing skill</a> among software engineers by LinkedIn. As an experienced native iOS developer who converted to Flutter 2 years ago and never looked back, I have a vested interest in watching the Flutter community succeed. So how should we interpret the SwiftUI announcement?</p><h3>What is declarative UI programming anyway?</h3><p>For those new to the topic, I want to briefly describe what <a href="https://flutter.dev/docs/get-started/flutter-for/declarative">declarative UI</a> programming actually is. So, it turns out that writing UI code is arguably the most complicated part of any modern application. Today’s mobile/desktop/web apps have to be <a href="https://en.wikipedia.org/wiki/Responsive_web_design">responsive</a>, handle device rotation, <a href="https://medium.com/@rwbutler/dynamic-type-in-ios-with-typographykit-9ed0ac5dbf64">dynamic font sizes</a>, light/dark mode, different themes, user customizations, role-based permissions, feature-flagging, and A/B testing. Now throw a couple of animations on top of all that. Oh yeah, and make everything delightful. And finish it by yesterday.</p><p>Before declarative UI programming, you would typically write your code in the following fashion: Handle the login button. Show the busy spinner. Call the backend. Hide the busy spinner. Redirect to the home screen. Show a popup on failure. In this “imperative” paradigm, you directly change individual parts of your UI in response to various events. Seems simple, but as an app gets more complex, it gets harder to update without things breaking unexpectedly. Things get complicated real fast. It becomes difficult to see the relationship between events and handle edge cases. That’s why sometimes you see apps in bizarre, inconsistent UI’s. It is the result of a combination of states that the developers did not expect.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*dOBCtzU3LXpteBGb_JAstQ.png" /><figcaption>When imperative UI programming goes wrong.</figcaption></figure><p>In contrast, in a “declarative” paradigm, the user interface is “declared” as a function of some data that represents it. That data is called <em>state</em>. As that state changes, the UI updates automatically. So, using the same example above: If no user, show login. If user, show home. If busy, show spinner. If failure, show error. The difference is that all the different states are accounted for in one place, preventing unexpected or inconsistent results. The result is usually:</p><ul><li>Vastly reduced complexity</li><li>Fewer lines of code</li><li>Improved code quality</li><li>Reduced development times</li></ul><p>It’s no wonder that developers love it. So Apple joining the party is kind of a big deal. It validates the declarative paradigm for the whole Apple community.</p><h3>What does this mean for Flutter?</h3><p>I love Flutter. It took what React Native started and ran with it. With its native performance, zero dependencies on native platform UI components, and ability to support iOS, Android, Mac, Windows, IOT, and Web, I am convinced that it is the best choice for modern application development. I am also amazed at how it has captured the mindshare of beginners and experienced native mobile developers alike. I do want to see it succeed.</p><p>In the immediate term, SwiftUI will probably reduce the incentive for Apple-only developers to adopt Flutter. Developers will be able to receive many of Flutter’s benefits including declarative UI architecture as well as hot reload, which will alleviate the pain of Swift’s <a href="https://github.com/fastred/Optimizing-Swift-Build-Times">famously slow compile times</a>. However, since SwiftUI only works on iOS 13 and up, apps will still have to support the old imperative style for several years before fully transitioning. That means potentially maintaining two entirely separate UI codebases for a long time!</p><blockquote>With Flutter, Apple developers will see that they can use the same declarative UI techniques they have already learned, but also run their code on many more platforms.</blockquote><p>In the longer term I think that Flutter will ultimately benefit from SwiftUI. Inevitably, the pressure will mount on Apple-only developers to port their apps to other platforms such as Android, Windows, and Web. With Flutter, Apple developers will see that they can use the same declarative UI techniques they have already learned, but also run their code on many more platforms. At that point, Flutter will be there waiting with open arms. Interesting in getting a head start? <a href="https://verygood.ventures/contact">Contact us</a>!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*nZdqzH6_6qElAb-5AuAtAg.png" /><figcaption><a href="http://verygood.ventures/">Very Good Ventures</a> is the world’s premier Flutter technology studio. We built the first-ever Flutter app in 2017 and have been on the bleeding edge ever since. We offer a full range of services including consultations, full-stack development, team augmentation, and technical oversight. We are always looking for developers and interns, so <a href="https://angel.co/very-good-ventures/jobs">drop us a line</a>! Tell us more about your experience and ambitions with Flutter.</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6d5898f7adf7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/what-swiftui-means-for-flutter-6d5898f7adf7">What SwiftUI Means for Flutter</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Under the Hood with Flutter for Web]]></title>
            <link>https://medium.com/flutter-nyc/under-the-hood-with-flutter-for-web-bc0d5ce1c11e?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/bc0d5ce1c11e</guid>
            <category><![CDATA[mobile-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Wed, 08 May 2019 13:37:33 GMT</pubDate>
            <atom:updated>2019-05-08T13:37:33.093Z</atom:updated>
            <content:encoded><![CDATA[<p>An inside look at how we built the NY Times <a href="https://www.nytimes.com/games/prototype/kenken">KENKEN App</a> at Google I/O ‘19</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*iRu1e1L-RyCBKlqnSmaYAw.gif" /><figcaption><a href="https://www.nytimes.com/games/prototype/kenken#/">https://www.nytimes.com/games/prototype/kenken</a></figcaption></figure><p>On May 7, 2019 the tech world watched with amazement as Google finally released the first public preview of <a href="https://flutter.dev/web">Flutter for web</a> (formerly known as Hummingbird). When it was first announced at <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwj_94K-kIniAhUsc98KHcxLBqEQFjAAegQIBhAC&amp;url=https%3A%2F%2Fdevelopers.google.com%2Fevents%2Fflutter-live%2F&amp;usg=AOvVaw3-ehgRE-pQaepdOm95x3t0">Flutter Live</a> in December 2018, it came as a shock to many who saw <a href="http://flutter.dev/">Flutter</a> as purely a framework for building cross-platform mobile apps. Together with the announcement of <a href="https://github.com/google/flutter-desktop-embedding">Flutter Desktop Embedding</a>, it was clear that the <a href="https://flutter.dev/">Flutter</a> project was much more ambitious than we had previously thought.</p><p>With Flutter apps now capable of running on iOS, Android, macOS, Windows, Web, IoT, and soon <a href="https://en.wikipedia.org/wiki/Google_Fuchsia">Fuchsia</a>, we are witnessing Google’s complete vision for creating the <strong>world’s first universal UI platform</strong>. This is a veritable game changer for application developers everywhere, who now can deliver applications for all these platforms from a single codebase. Not to mention that these apps are higher quality, built by fewer developers, and in drastically less time.</p><p>My name is <a href="https://medium.com/@martinrybak">Martin Rybak</a>, and I am the organizer of the <a href="http://flutter.nyc/">New York Flutter Meetup</a>, one of the largest Flutter meetups in the world. I am also a co-organizer of the first <a href="https://flutterhackathon.com/">International Flutter Hackathon</a> on June 1 (be sure to join!). I have the privilege of working for <a href="http://verygood.ventures/">Very Good Ventures</a>, the company that built the <a href="https://www.youtube.com/watch?v=kfd-oLypqFI">Hamilton app</a> and the <a href="https://github.com/flutter/slideplayer">Slides app</a> from Flutter Live. When Google Executive Tim Sneath called us to see if we could build a demo app for the <a href="http://nytimes.com/">New York Times</a> that would run on mobile, desktop, and web, we were thrilled. We would be one of the first teams outside of Google to ever use Flutter for web! Our challenge was to update the current <a href="https://en.wikipedia.org/wiki/Adobe_Flash">Adobe Flash</a>-built <a href="https://www.nytimes.com/puzzles/kenken">KENKEN</a> app on The New York Times website.</p><p>We only had 48 hours to build a working prototype that would validate its feasibility, and we happily accepted the challenge! I’m happy to say that it worked, and over the next several weeks we worked closely with the New York Times team to explore and implement multiple designs, animations, and features. While we can’t share our final source code, we are happy to share our experiences and some of the challenges we faced.</p><h3>First Impressions</h3><p>We collectively held our breaths as we first ran Flutter for web for the first time. Watching the well-known Flutter sample app appear in a browser brought a huge smile to our faces — we were web developers again, but without the JavaScript! 😁 Looking at the example Flutter code, the first thing that stood out was that the web imports were slightly different than mobile:</p><pre>import &#39;package:flutter_web/material.dart&#39;;<br>import &#39;package:flutter_web_ui/ui.dart&#39;;</pre><p>Since Dart has no preprocessor, there was no compile-time way to share these with the standard mobile imports (Google’s goal is to eventually merge Flutter web into the main Flutter framework). Also, images and fonts had to go into a separate location on the filesystem and be declared in separate manifest files. So we decided to separate our Git repo into 3 branches: <em>master</em> (web), <em>mobile</em>, and <em>desktop</em>. To minimize merge conflicts, we decided to do all of our development off of <em>master</em> (web) and then periodically merge changes into the <em>mobile</em> and <em>desktop</em> branches. Any mobile- or desktop- specific code changes, such as import fixes, would go directly into their respective branches.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/784/1*8looG68AnuR4YrrVldlubw.png" /><figcaption>The final game board.</figcaption></figure><p>We had a basic working prototype in 48 hours, which is truly a testament to Flutter’s development velocity. One developer worked on the game board and the other on the overall layout and game play. At the core of the game is a Game model which validates and stores game data, maintains the timer, and detects wins. Game data is fetched from the backend API via a separateApiManagerthat uses the <a href="https://pub.dev/packages/http">http</a> package, which worked beautifully. The format of the API response was a little tricky, so we created a GameData parser to convert it into a more usable format. The Board widget then knows how to render itself using this data, and interacts with the Game model using touches, mouse, and keyboard events. The rest of the code consists of widgets and custom painters.</p><h3>Debugging</h3><p>To run a Flutter web app in debug mode with hot reload enabled, run the following command (provided .pub-cache/bin is in your <a href="https://en.wikipedia.org/wiki/PATH_(variable)">PATH</a>):</p><pre>webdev serve --auto=restart</pre><p>This launches a web server at <a href="http://localhost:8080/">http://localhost:8080</a> which you can open in any desktop browser. We used a tool called <a href="https://en.wikipedia.org/wiki/PATH_(variable)">ngrok</a> to access the site on our mobile test devices. Hot reload works exactly as expected, and maybe even better than on mobile! Flutter for web comes with a file listener that refreshes the browser whenever it detects any code changes. Unfortunately though, you cannot yet connect the IDE debugger to a running Flutter web app. However, amazingly, you <em>can</em> debug from within Chrome using <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjGwNmOn4niAhWjSt8KHYhwAKIQFjAAegQIBRAC&amp;url=https%3A%2F%2Fdevelopers.google.com%2Fweb%2Ftools%2Fchrome-devtools%2F&amp;usg=AOvVaw3FzWxfRd4AQ8ZEIxyYwamX">DevTools</a>. Flutter for web uses <a href="https://en.wikipedia.org/wiki/Minification_(programming)#Source_mapping">source maps</a> which let you see your original <strong>Dart</strong> code directly in the browser! (<strong>Note</strong>: this is only useful in debug mode. Release builds use minification to obfuscate your code.) There you can set breakpoints, examine the call stack, and view and edit variables. You can also use the <em>Network</em>, <em>Performance</em>, and <em>Memory</em> tools to see how your app performs in those areas.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/869/1*Qq6sqRLRZ4elQRtkRso_jg.png" /><figcaption>Dart source code, right in Chrome DevTools! 😲</figcaption></figure><p>Speaking of release builds, what exactly gets shipped in a Flutter web application? Turns out it’s just a single-page web app with all of your Dart code and package dependencies compiled into minified Javascript! This is thanks to Dart’s powerful and battle-tested <a href="https://webdev.dartlang.org/tools/dart2js">Dart to Javascript transpiler</a>. Pretty amazing!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/524/1*KmN4fP6LMyokVk06Gz6Ixg.png" /><figcaption>It’s all just Javascript.</figcaption></figure><h3>Performance</h3><p>Flutter for web was still a bit raw so we did our best to report any issues. There were some problems involving text rendering and input, but drawing and animations worked amazingly well! (Under the hood, Flutter for web draws most elements to the canvas directly except text, which is rendered by the browser).</p><p>Originally, we built the Board widget using a GridViewcontaining customTile widgets. However, we ran into a few issues. First, there were visible artifacts between the tiles which is a <a href="https://github.com/flutter/flutter/issues/29702">known bug</a>. Second, we ran into some slowness in the build() method that was a result of the large amount of text widgets we were using. To fix both problems, we opted to use a CustomPainter to draw the board lines and render the text directly onto the canvas using a TextPainter. However it was still slow for the animation-intensive end of game display. In release mode for the 8x8 grid we were seeing an average of 46ms for the paint() method. In order to prevent dropped frames, we had to get it down to less than 16ms. So we tried an unorthodox technique and converted the numeric characters directly into Path objects. Doing this dropped the paint() method down to less than3ms. The Flutter for web team has been working hard on improving performance, so it is quite possible that these optimizations are no longer necessary. Still, it’s good to know that if you run into any performance bottlenecks, you can always drop down to lower layers.</p><h3>Keyboard and Mouse Input</h3><p>Listening to data from the keyboard was a bit tricky. On Android and macOS we could use RawKeyboard.instance.addListener() but the codes for the various input keys were different. On Web we had to use window.onKeyDown.listen()from the <a href="https://pub.dev/packages/html">html</a> package, which means a code divergence between web and mobile. To solve these this, we created a KeyboardService class that acts as an abstraction layer for all keyboard input. At runtime, a factory constructor returns the correct instance for the current platform. This approach also supports the on-screen keyboard used by the mobile layout, so no additional code is needed. Mouseover support for Web, Android, and Desktop was added in a similar way, with differing implementations hidden behind a common abstraction we called HoverDetector.</p><h3>Responsive Design</h3><p>A big challenge for web compared to building for mobile is supporting variable browser window sizes. This is known as <a href="https://en.wikipedia.org/wiki/Responsive_web_design">responsive design</a>. Whereas on mobile there are a relatively standard set of screen ratios, a browser window can be resized to any height and width. How can you ensure that a Flutter web app looks good on a nearly infinite set of screen sizes? There are a few possible techniques:</p><ul><li><strong>Use breakpoints</strong>. Using a root LayoutBuilder, you can change the layout of the whole app based on screen height/width. You can show a “tablet” version on wider screens and a “mobile” version on narrower screens. For example, on narrow screens we make the headers shorter as well as show the on-screen input keyboard.</li><li><strong>Scale content</strong>. To make a widget “scale” to fit any size, you can use a LayoutBuilder to make things like font sizes, border widths, shadows, corners, and margins all scale proportionally relative to a base size. For example, the game board scales perfectly no matter what size it is.</li><li><strong>Use scrollable containers</strong>. If scaling is not desirable, you can embed your widget in a scrollable container such as aSingleChildScrollView. The initial game selector screen behaves like this.</li><li><strong>Enforce a minimum size</strong>. If the widget’s size constraints are simply too small to show your content correctly, you can simply show some text asking the user to increase the size of their browser window. We will probably implement this in the future, as the game board is simply unusable past a certain size.</li></ul><h3>End Game Animation</h3><p>One of the most eye-catching moments in the app is after the user wins a game, and we show a complex animation that converts the board into a rocket ship! This animation was originally designed in <a href="https://www.adobe.com/products/aftereffects.html">After Effects</a>, and is implemented 100% in Flutter. This would have been a great candidate for <a href="https://www.2dimensions.com/about-flare">Flare</a>, but unfortunately it isn’t yet supported on Flutter for web. We collaborated with <a href="https://medium.com/u/91cb19edfc82">Simon Lightfoot</a> to create this complex yet delightful animation. How did we do it?</p><p>The main transition is a standard Hero widget animation. When the modal appears, Flutter seamlessly transitions the source Board into a read-only version of the Boardat the destination. When the modal is dismissed, the animation is automatically reversed. However, Hero animations don’t work with PopupRoutenavigation routes (modal transitions), so we had to create a custom PageRoute subclass.</p><p>After the Hero animation completes, a number of animations kick off simultaneously. The background begins shooting stars at random locations, built with a CustomPainter. The flame effect then begins and animates to the left. This was also made with a CustomPainter that is simply rotated by 45° and anchored to the center of the board. Both the board and flames experience a brief overshoot animation before settling down with a persistent shake animation. Finally, the text flies in at an angle with a fade transition. These animations were all accomplished using the powerful AnimatedBuilder widget, which performs transforms on widgets efficiently without triggering a rebuild on every frame.</p><h3>Final Thoughts</h3><p>It was an absolute pleasure to have worked on Flutter for web so early on. We had the chance to work closely with the awesome Flutter team at Google and resolve various issues. Development continues at a breakneck pace, especially in overall stability and performance. Over the next few weeks we look forward to working with the New York Times team to bring this game, and perhaps more, to production soon.</p><p>That said, Flutter for web is still a work in progress. Here are some areas of improvement that we’ve identified:</p><ul><li>Web-specific code that requires the <a href="https://pub.dev/packages/html">html</a> package. Keeping separate web/mobile/desktop branches is tricky.</li><li>No native debugger. While Chrome DevTools is great, working with the IDE debugger is a superior experience.</li><li>Offline persistent storage that works across web &amp; mobile.</li><li><a href="https://api.dartlang.org/stable/2.3.0/dart-isolate/Isolate-class.html">Dart isolates</a> are not supported in Flutter for web. Javascript is single-threaded.</li><li>Text input does not yet match platform conventions.</li><li>Selecting/copying of text is not yet supported.</li><li>The browser back button works just like the Android back button, but the forward button is not supported yet.</li><li>Making Flutter for web more SEO-friendly.</li><li>Printing with a @media stylesheet isn’t yet supported.</li><li>Anything else you find? Please <a href="https://goo.gle/flutter_web_issue">file an issue</a>!</li></ul><p><em>Special thanks to Albert Larzidabal, Kevin Gray, Simon Lightfoot, Kevin Moore, and Yegor Jbanov.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*iAH_deq1iUkJZp7msD5-lA.png" /></figure><p><a href="http://verygood.ventures/">Very Good Ventures</a> is the world’s premier Flutter technology studio. We built the first-ever Flutter app in 2017 and have been on the bleeding edge ever since. We offer a full range of services including consultations, full-stack development, team augmentation, and technical oversight. We are always looking for developers and interns, so <a href="https://angel.co/very-good-ventures/jobs">drop us a line</a>! Tell us more about your experience and ambitions with Flutter.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bc0d5ce1c11e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/under-the-hood-with-flutter-for-web-bc0d5ce1c11e">Under the Hood with Flutter for Web</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Avoiding the On-Screen Keyboard in Flutter]]></title>
            <link>https://medium.com/flutter-nyc/avoiding-the-on-screen-keyboard-in-flutter-ae0e46ecb96c?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/ae0e46ecb96c</guid>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[keyboard]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Thu, 14 Feb 2019 14:40:42 GMT</pubDate>
            <atom:updated>2019-02-16T21:39:19.866Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*cUyHvPNuSBkCBq17CtTueA.gif" /><figcaption>Every colored area is wrapped in its own <a href="https://pub.dartlang.org/packages/keyboard_avoider">KeyboardAvoider</a>.</figcaption></figure><p>Newcomers to both native iOS and Android development often struggle with what <em>should</em> be an easy problem: making room for the on-screen software keyboard. There are many different solutions, some of which are built-in and some of which use third-party packages. How does Flutter handle this scenario?</p><p>Flutter comes with a built-in Scaffold widget that automatically adjusts the bottom padding of its body widget to accomodate the on-screen keyboard. However, it comes with 2 major caveats:</p><ol><li>It pushes <em>all</em> content up, which you may not want.</li><li>It assumes that it fills the whole screen, which it may not.</li></ol><p>In the first case, consider the common scenario of a search field above a results view with a floating action button (FAB) on bottom. While the text field is active, I want to avoid the keyboard so that users can scroll to the last row in the list. I therefore embed my widget in a Scaffold. However, by doing so it also pushes up my FAB, which is not what I want.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/250/1*1lhb1xlsc4jrRdMTc6FiqQ.gif" /><figcaption>Scaffold pushing up the FAB with the keyboard.</figcaption></figure><p>In the second case, I have a tablet app and want to make sure that the left and right panels are not obscured by the keyboard. Notice that they do <em>not</em> extend all the way to the bottom of the screen. But if I wrap them both in aScaffold, their bottoms will both shift up by the <em>entire height </em>of the keyboard, which is just flat-out incorrect. Not to mention that it feels extremely inappopriate to use a Scaffold in this way, since each comes with its own FAB, drawer, bottom sheet, etc. We can conclude that a Scaffold is not the right tool for the job.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*TW43_HxRfeGDklqdlY3yUg.gif" /><figcaption>Scaffolds always adjust their bottom padding to the full height of the keyboard.</figcaption></figure><p>So what can we do?</p><p>We can get the height of the on-screen keyboard by doing a MediaQuery and accessing its viewInsets.bottom property. Then we can wrap our widget in a simple Padding widget that consumes this value. Because MediaQuery is an InheritedWidget, our widget will automatically rebuild whenever the app’s viewInsets change:</p><pre>class MyWidget extends StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    final bottom = MediaQuery.of(context).viewInsets.bottom;<br>    return Padding(<br>      padding: EdgeInets.only(bottom: bottom),<br>      child: Placeholder(),<br>    );<br>  }<br>}</pre><p>However we still have the same problem as the Scaffold: our widget assumes that it fills the entire screen. <strong>We need the bottom padding to equal the amount the widget is actually overlapped by the keyboard</strong>. How can we do that?</p><p>The short answer is that we cannot; at least not using widgets alone. The reason is that in Flutter, widgets are <strong>only short-lived immutable blueprints</strong> of our content. The Flutter engine uses those blueprints to layout and paint our actual content on the screen, which lives in a separate place called the <strong>render tree</strong>.</p><p>This sounds scary but it’s really not — if you’ve ever done any native mobile or web development you are already intimately familar with the concept of a view tree (DOM on web). Whenever you update a view by changing its text or color, you are updating the equivalent of the render tree in Flutter. In fact, the whole philosophy behind React and Flutter is to abstract away this “imperative” style of UI programming with a “declarative” one. Instead of telling the UI <em>how</em> to update, we tell it <em>what</em> we want it to look like, and let the framework do the hard work of actually figuring out what views to update. In Flutter, <strong>widgets</strong> are this mechanism. Behind the scenes, they are blueprints for updating the <strong>render tree</strong>.</p><p>So how do we find out how much our widget overlaps with the on-screen keyboard? First, we need to find the RenderObject for our widget in the render tree. We do that by calling findRenderObject() on our widget’s context. A BuildContext just represents a widget’s unique location in the render tree.</p><pre>final renderObject = context.findRenderObject();</pre><p>Now that we have it, we need to get its coordinates on the screen:</p><pre>final renderObject = context.findRenderObject();<br>final renderBox = renderObject as RenderBox;<br>final offset = renderBox.localToGlobal(Offset.zero);<br>final widgetRect = Rect.fromLTWH(<br> offset.dx,<br> offset.dy,<br> renderBox.size.width,<br> renderBox.size.height,<br>);</pre><p>Next we need to find the coordinates of the on-screen keyboard. We can get this from the global window class provided by the dart:ui package. The only wrinkle here is that we need to convert from pixels to points.</p><pre>final keyboardTopPixels = window.physicalSize.height — window.viewInsets.bottom;<br>final keyboardTopPoints = keyboardTopPixels / window.devicePixelRatio;</pre><p>Now we can implement our logic. First, let’s figure out how much the keyboard overlaps our widget:</p><pre>final overlap = widgetRect.bottom — keyboardTopPoints;</pre><p>We can now use this value to update our bottom padding. Let’s do this by making our widget stateful and introducing a new state variable called _overlap:</p><pre>class _MyWidgetState extends State&lt;MyWidget&gt; {<br>  double _overlap = 0;</pre><pre>  @override<br>  Widget build(BuildContext context) {<br>    return Padding(<br>      padding: EdgeInsets.only(bottom: _overlap),<br>      child: Placeholder(),<br>    );<br>  }<br>}</pre><p>Now we can update our _overlap variable by calling setState(), which will cause our widget to rebuild. Let’s also make sure that the overlap is not negative.</p><pre>if (overlap &gt;= 0) {<br>  setState(() {<br>    _overlap = overlap;<br>  });<br>}</pre><p>Now where do we put all this code? Flutter has a nifty mixin calledWidgetsBindingObserver that provides adidChangeMetrics() method which gets called whenever the window’s metrics change:</p><pre>@override<br>void didChangeMetrics() {<br>  …<br>}</pre><p>And that’s it! Putting it all together into a working example you can paste right into your main.dart file:</p><pre>import &#39;package:flutter/material.dart&#39;;<br>import &#39;dart:ui&#39;;</pre><pre>void main() =&gt; runApp(MyWidget());</pre><pre>class MyWidget extends StatefulWidget {<br>  _MyWidgetState createState() =&gt; _MyWidgetState();<br>}</pre><pre>class _MyWidgetState extends State&lt;MyWidget&gt; with WidgetsBindingObserver {<br>  double _overlap = 0;</pre><pre>  @override<br>  void initState() {<br>    super.initState();<br>    WidgetsBinding.instance.addObserver(this);<br>  }</pre><pre>  @override<br>  void dispose() {<br>    WidgetsBinding.instance.removeObserver(this);<br>    super.dispose();<br>  }</pre><pre>  @override<br>  Widget build(BuildContext context) {<br>    return MaterialApp(<br>      home: Column(<br>        children: &lt;Widget&gt;[<br>          Material(<br>            child: TextFormField(<br>              initialValue: &quot;Edit me!&quot;,<br>            ),<br>          ),<br>          Expanded(<br>            child: Padding(<br>              padding: EdgeInsets.only(bottom: _overlap),<br>              child: Placeholder(),<br>            ),<br>          )<br>        ],<br>      ),<br>    );<br>  }</pre><pre>  @override<br>  void didChangeMetrics() {<br>    final renderObject = context.findRenderObject();<br>    final renderBox = renderObject as RenderBox;<br>    final offset = renderBox.localToGlobal(Offset.zero);<br>    final widgetRect = Rect.fromLTWH(<br>      offset.dx,<br>      offset.dy,<br>      renderBox.size.width,<br>      renderBox.size.height,<br>    );</pre><pre>    final keyboardTopPixels = window.physicalSize.height - window.viewInsets.bottom;<br>    final keyboardTopPoints = keyboardTopPixels / window.devicePixelRatio;<br>    final overlap = widgetRect.bottom - keyboardTopPoints;</pre><pre>    if (overlap &gt;= 0) {<br>      setState(() {<br>        _overlap = overlap;<br>      });<br>    }<br>  }<br>}</pre><p>Hopefully this helps make the render tree a slightly less mysterious topic for you. Don’t be afraid to drop down to this layer when you need some more advanced functionality in Flutter. Just remember that the widget’s render object is only updated <em>after</em> the build() method returns.</p><p>There are some more advanced features you could still add, such as animating the padding change, automatically wrapping content in a ScrollView, and automatically scrolling to a focused text field. For these cases, feel free to use the <a href="https://pub.dartlang.org/packages/keyboard_avoider/">KeyboardAvoider</a> widget we have published on <a href="https://pub.dartlang.org/packages/keyboard_avoider/">pub.dartlang.org</a>. Your implementation might be different. Pull requests are always welcome. Enjoy!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ae0e46ecb96c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/avoiding-the-on-screen-keyboard-in-flutter-ae0e46ecb96c">Avoiding the On-Screen Keyboard in Flutter</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing Flutter NYC!]]></title>
            <link>https://medium.com/flutter-nyc/introducing-flutter-nyc-c9e327ad050f?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/c9e327ad050f</guid>
            <category><![CDATA[google]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[new-york-city]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Tue, 12 Feb 2019 16:40:18 GMT</pubDate>
            <atom:updated>2019-02-12T16:40:18.794Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*-8v7Rg-iNPa53SLA2PICXA.png" /></figure><p><a href="http://flutter.nyc/">Flutter NYC</a> is one of the <a href="https://www.meetup.com/find/?allMeetups=false&amp;keywords=flutter&amp;radius=Infinity&amp;userFreeform=New+York%2C+NY&amp;mcId=z10014&amp;mcName=New+York%2C+NY&amp;sort=member_count&amp;eventFilter=mysugg">top 5 global</a> meetup groups dedicated to <a href="http://flutter.io/">Flutter</a>, Google’s new framework for building multi-platform mobile apps for iOS, Android, and more.</p><p><a href="https://www.meetup.com/flutter-nyc/?action=join">Join the meetup!</a></p><p>New York City’s thriving and diverse tech scene is a perfect home for this amazing new technology. Whether you are just starting a new Flutter project, or an experienced dev looking to discuss advanced topics, this group is where you belong! We meet every month to discuss the latest trends in Flutter, share educational content, and demo amazing new Flutter projects. See videos of our talks on our <a href="https://www.youtube.com/channel/UCggH9mMAde-CTWCYC__obiw">Youtube channel</a>.</p><p>We’ve already hosted some of the biggest names in the Flutter community, including core Flutter team members, the team that built <a href="https://verygood.ventures/">the flagship Hamilton app</a>, <a href="https://medium.com/u/369e2e1c1beb">Nick Manning</a>, and many others. Most importantly, we’ve got a full line-up of meetups planned for the rest of 2019!</p><p>Are you interested in speaking? Speakers and hosts are always wanted — send us your ideas (<a href="https://goo.gl/forms/PBAZOtU0xrgnKfD72">https://goo.gl/forms/PBAZOtU0xrgnKfD72</a>)!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9e327ad050f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/introducing-flutter-nyc-c9e327ad050f">Introducing Flutter NYC!</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter Live ’18 Recap with Martin Aguinis]]></title>
            <link>https://medium.com/flutter-nyc/flutter-live-18-recap-with-martin-aguinis-428df6a5b664?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/428df6a5b664</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[new-york]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[google]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Fri, 28 Dec 2018 19:31:40 GMT</pubDate>
            <atom:updated>2019-02-18T02:13:48.509Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Cas8nw39YZoP4hLplaIzlw.jpeg" /><figcaption>The following is a transcript from a <a href="https://www.meetup.com/flutter-nyc/events/255777347/">Flutter NYC</a> meetup that was held on December 4, 2018. See the <a href="https://www.youtube.com/watch?v=qMRPImdqU9w&amp;t=229s">full video</a>.</figcaption></figure><p><a href="https://medium.com/u/a53992d973c9">Martin Rybak</a>: Tonight we are super proud to welcome our special guest Martin Aguinis who is the Marketing Lead for <a href="https://flutter.io/">Flutter</a> at Google. You may have seen him in many videos online including the new <a href="https://www.youtube.com/watch?v=CXedqMlLo7M">Flutter Widgets 101</a> series. He is stopping by New York on his way home from London where he helped organize the <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwix-ITpxb7gAhUQuVkKHXg4AOgQFjAAegQIABAC&amp;url=https%3A%2F%2Fdevelopers.google.com%2Fevents%2Fflutter-live%2F&amp;usg=AOvVaw3-ehgRE-pQaepdOm95x3t0">Flutter Live</a> event, so let’s give him a warm Flutter NYC welcome!</p><p><a href="https://medium.com/u/984284ef4c17">Martin Aguinis</a>: Alright, thanks so much! Thanks Martin for organizing this and thank you so much everyone for being here on a Friday night. I know there’s a lot of excitement happening with Flutter but there’s also a lot of other things happening in New York so I really appreciate you being here. So before I get started, as I was putting these slides together I realized I actually have no idea what level of familiarity everyone has with Flutter or with mobile apps or Google so I just wanted to get a little bit of a sense of that so that I can maybe adjust the presentation to fit the audience. So, who here is working on some sort of Flutter project? Who here is a mobile app developer? What about a developer in general? Any business-focused? Who here knows very little about Flutter? And who here was able to catch Flutter Live this week? Awesome, so there’s a good mix. We’ll try and therefore go both a little bit high level briefly and then deep dive into certain parts too — and we’ll definitely leave some room for questions as well. One of my favorite parts is just getting to see what type of questions you have and obviously hope to answer them; if not I have luckily some other people on the team that can help.</p><p>Actually one more thing, who’s ever heard one of my talks before, whether online or in person? Great, so some of you might have seen a few of these slides already, but what I want to do is first start by talking a little bit about the mobile landscape in general and why Google cares so much about Flutter and innovating in that space. Then we’ll talk about Flutter Live and some of the announcements we heard. Then we’ll hear from Will Larche from our team who runs our Material Design and Flutter collaborations he’s done excellent work. Will was on stage as well at the event. We’ll also hear from Clay Elliot about his experience with Flutter and we’ll take some questions, so let’s get started.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*tQoYrEjmjiRvHysSGPvVaA.png" /></figure><p>I wanted to start with this fact, which is that from 2016 to 2022 the mobile app economy is growing from $1.31 trillion to $6.35 trillion. Absolute numbers for me are sometimes hard to conceptualize so that’s like saying that every human being on this planet has contributed $835! This is partly because the number of apps actually downloaded are growing as well.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*73JLz_zSkeyWR-aY4LkxoQ.png" /></figure><p>As you can see in this chart, in 2018 we have about 205 billion downloads a year, and that’s going to grow to about 258 billion in 2022. Pretty crazy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*dfrwjt3PsJypgrrfSZARIg.png" /></figure><p>Now this is another really interesting study which is taking the top 1,000 mobile apps versus the top 1,000 mobile web properties. In other words, apps and the mobile web have done very well, and if you compare those along the same range you’ll realize that there’s a 10x in terms of the time spent on mobile apps. So it’s really important to have a good experience on apps and if done right they can engage your users very well. And something we did as Google, one of the studies we did, was trying to understand how do you boost apps’ usage? If everyone knew the answer that none of us would be here today, right? So the study results had a consistency of eliminating friction which means making it a lot easier for your users, very simple designs, somewhat intuitive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*PR4vm_moYhCK6waErsxE1Q.png" /></figure><p>Sometimes you look at apps — my first app back in college that I made up was basically like an Uber for the fraternity and sorority systems called Greek Ride — and the way it works is you would press a button and they would help you get to your organization. And at first we had like five tabs in there and it was really hard to use and then we realized who our target demographic was for this app and we realized, wait a minute, we only need one button right? Make it very simple, one use case, and that’s it! But that’s something we saw in this study too, which is simplicity, intuitiveness, being consistent across devices. That’s not very easy to do, right? And again, if you’ve seen this before maybe don’t say the number, but if you haven’t, let’s play a little game of roulette to try and understand the challenges in the mobile space.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*-ZAIbTdZsQItaun61fD-iA.png" /></figure><p>So can someone yell out a number 0 trough 36? 25? Alright let’s test your luck tonight. If we get 25 maybe you can come up here and give the rest of this talk. Alright, 17 so you didn’t get it right. But don’t worry, you only had a 3% chance of getting that right. And according to AppsFlyer, only about 3% of users remain active on an app after 30 days. So if we were to take an average app from the Play or iOS store, and a hundred people were to download it today, only around 3 of them would be active users after a month! So it’s like playing game of roulette, right? But that’s not the only challenge we have with mobile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*aBuNalKEHl1MMlXBHBIcVA.png" /></figure><p>A lot of you might be familiar with some of these challenges. On the business side we have things like time to market. You have a great idea, by the time I executed on it there’s already 15 apps like it. Fragmentation and agility — especially with different app stores nowadays. Having to coordinate between your designers and your developers and having 2 split codebases. And also testing and prototyping — a lot of times you just want to build out the concept and start iterating from it, instead of having to invest thousands of dollars into making an app.</p><p>Some of the technical reasons which you all might be familiar with, and one of the reasons why people really like Flutter, are having to have split code bases. So if you have to make an app as a brand — in the US it’s 50/50 Android/iOS market penetration and the rest of the world’s it’s about 80% Android/20% iOS, so it’s still a ridiculous amount of users are using both. So obviously many times brands have to have those but even let’s assume you have to just have one, let’s just assume you only want to make an iOS or Android because you’re biased — I have both phones, so as you can see I’m not that biased — but even if you only have to have one, you still have to coordinate between the designers and the developers. So, a designer will make this beautiful app in InDesign or on Sketch and give it to the developer and then the final product, and they’ll be like, what happened? This is not exactly how I wanted it. They have to make compromises. A few other other problems there.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*Zm7m3Oph_oQm8nUgJ7eNTg.png" /></figure><p>So in other words, this is my favorite visualization that describes this dilemma. So on the left you can see what 80% of people nowadays still do, which which is develop two separate iOS Android applications. At the end you get that castle but, that maze represents a lot of those challenges that I just said. It takes a lot more time, you have to give double the effort. So what’s the alternative before Flutter? Well, you can use a traditional third-party cross-platform solution. Now, we’ll dive a little bit into technologically why this is, but long story short, most solutions like PhoneGap, Cordova, React Native, a lot of them use Javascript, so essentially you’re passing the bridge, you’re building it with a web language and it’s converting into native code so you’re not technically building a native app, and so that means that in that process it slows the app down sometimes, it’s just not fully native. We’ve all been there where, I mean nowadays we all have such high expectations in our apps that we assume it’s going to scroll a certain way or do some behavior, and when it does of course we’re not very grateful for it, but when it doesn’t, you know forget ever using that app again, especially with that 3% number I gave you.</p><p>So that’s where Flutter comes in. It’s funny, because I was giving a talk similar to this a year ago and even at Google people were like, what’s Flutter? And it’s amazing to see the amount of awareness that has grown, and now as marketer my challenge no longer becomes raising awareness, that’s always a challenge, but it’s also making sure we are clearly articulating the value proposition, clearly articulating what Flutter is for, and as you’ll hear from the Keynote that happened, it’s beyond mobile. But I thought what I’d do is show you a quick sizzle reel that we made in one minute of this past week and the event and then I’ll go through the rest, so let’s see if this works.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*7t-GMi8pPRAhy46mvIauAQ.png" /></figure><p>Great so here are some pictures from the event itself. That claw machine on the on the left — I was in Shanghai, China, and we went into this place called Pig Pink and it’s five stories of just claw machines, and everything is pink. And when I’m there — we have this mascot called Dash, which some of you might have, I’m like, that would be so cool if we had it — so as a joke I pitched it to our Events Coordinator, hey we should have a claw machine at the event! Two months later I get a deck to approve some of the branding and they’re like, oh this is where we’re going to place the claw machine. I’m like, no way, no way! I show up, there’s a claw machine with Dashes and the line is literally out the door. That was the most popular thing. So, if you have an idea you think is stupid, pitch it, I promise you, great advice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*U1VHCFiiJs4L8tx5PM8HvA.png" /></figure><p>But anyway, this was the event and it was great, but I think the most incredible part about this was not the physical event, but this was a global launch. And at Google usually we have dev summits like Chrome, Android, and a lot of the focus goes on the physical events, but we understand that most people can’t make it there. And I know a lot of you were in this New York City meetup this week, and I heard it was a lot of fun and you had your own cheering crowd going at certain moments, and I’m sure you have much more candid feedback then what we heard at the event itself. But it was amazing because we had over 150 viewing parties around the world, just people getting together watching this. And we actually did a <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=2&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjK_KCExr7gAhVJzlkKHQNpCtEQwqsBMAF6BAgCEAc&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D9WgQzB0UZOs&amp;usg=AOvVaw3SE0EK9vZjrB2E7jD4EKwr">My Flutter Story</a> campaign where we had people submit their Flutter stories from around the world, and it was amazing to see the diverse responses and that’s something that we’re very proud with Flutter. So thank you all for tuning in, those that did, and those that didn’t, the last few days for me and my team has been all about the recap videos and recordings, so now we have a nice 10-minute keynote, so if you don’t have an hour you can watch the 10-minute version which has all the highlights and skips out the part where Matt and Emily miraculously finish coding an app in like 10 minutes, it was pretty incredible.</p><p>So that was it, that was the event. Flutter 1.0. So I thought today for some of you in the audience that didn’t get to watch it, why don’t we do Flutter 1.0 in 10 minutes. So I’m going to give you the abridged version of Flutter 1.0 and after that I’ll bring up Will Larche to give a little bit more deep dive into some of the actual code and the demos that we showed. Hopefully no one’s timing because I’ve never timed myself here, but I really think I can keep it under 10 minutes, we’ll see.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*CYD_7UBySGf5aLhGc8E5IQ.png" /></figure><p>So, we use four pillars to describe Flutter. Flutter is beautiful, Flutter is fast, Flutter is productive, and Flutter is open. By beautiful — Flutter gives you you basically control over every pixel on the screen. So unlike general mobile app development, with Flutter, everything you write, every line of code is actually what shows up on the final app. There’s no process between what you’re coding as a developer or designer and what’s actually showing up on the phone. What that means is you have full control — this is a canvas, you’re basically an artist and as you can see from this example that came in two days on Twitter before the event, but people are just making these beautiful interfaces. And you saw the statistics on how much time individuals spend on mobile apps, so given that, being able to have these experiences will make a huge difference for organizations, for even smaller apps or startups. So you basically you don’t have to compromise between designers and developers and Will will definitely talk more about that.</p><p>The second one is that it’s fast. So, we use this high powered graphics engine called Skia. And Flutter compiles ahead of time, so you basically all the apps are running over 60 frames per second, so they’re incredibly quick. We’ve seen things like these gaming apps, <a href="https://www.2dimensions.com/about-flare">2Dimensions</a> which I’ll talk about in a bit, are able to do all these amazing animations and you don’t have to compromise. I mean, we’ve all been in that situation, usually it’s an airline app, but some sort of app, where you’re like what is this janky app, or this scrolling? We’ve all been there, and you’re waiting in the streets and you’re just waiting for something to scroll. We don’t want that, right? We want it to be really, really fast.</p><p>The third one is productive. We introduced something called stateful hot reload. What stateful hot reload is, it allows you to literally paint an app to life. So you write the Flutter code, or Dart code, and within milliseconds, you press a button and the app will change. So you can literally have a designer and developer sit next to each other and say, ok move this 1 pixel to the right, then hot reload, and it moves. What happens in other development environments is move this 1 pixel to the right. Ok, well something broke, come back in ten minutes, let me recompile it, let me port the app, let me see what happens. That doesn’t happen with Flutter. Let’s say that something does happen and the app breaks. It’s state-ful, which means it doesn’t lose state. There is a video of me talking about stateless widgets (shameless plug), but if you didn’t see it, the way it works is — if you break part of the app, let’s say this button broke, the app is still running, only that part would stop working, and then you could quickly hot reload with a fix, so it’s really easy to find that. As you can see here what’s happening is we’re changing the word clicked to push and when that happens we press hot reload and in 654 milliseconds it changes. But also it’s interesting as the business logic also changes, so we’re now changing it so that instead of adding, it subtracts and that works as well.</p><p>Finally, open. One of the things we’re most proud of is that Flutter is free and open source. It’s completely free and open source and same thing with the community. So Flutter is an open project, and what we mean by that, as Will mentioned that doesn’t always happen on private API’s, is we are very open to the the community and we have so many contributors that are outside of the Flutter team and outside of Google. So we’ve had thousands of packages and plugins that people like yourselves wrote for your apps and then put in Flutter for other people to use, whether it’s widgets or different platform API’s. So that’s really exciting because a lot of times one of us will be giving a talk and we’ll be like I’m not sure if that exists, and then we go on Github or StackOverflow and we look it up and someone’s already written something for it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*whoFaSYpF_79DSY-BT2L_A.png" /></figure><p>So what’s new with Flutter 1.0? A lot of you have already raised your hand saying you’ve already been following Flutter and we’ve heard your feedback and we really care about that, so these are some things we know that are very important that what we’ve been working that are new in this release. I won’t name all of them, but I think giving iOS a lot of love is important. A lot of times you want to have that brand-centric design, meaning like the <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwiXlN6Vyb7gAhXi1FkKHQ--ADQQFjAAegQICBAB&amp;url=https%3A%2F%2Fitunes.apple.com%2Fus%2Fapp%2Fhamilton-the-official-app%2Fid1255231054%3Fmt%3D8&amp;usg=AOvVaw1e58BdguTT1ecwc2aaETJT">Hamilton</a> app for example, looks very much like a Hamilton app, it doesn’t look like an Android or iOS app, but a lot of apps do want to have that Android or iOS feel, and we’ll talk about that in a sec. But we also have things like adding to existing applications. A lot of people are like oh, I’d love to use Flutter but I already have an app. I’ve good news for you! That’s what Alibaba did actually, and you can basically make certain parts of your app, if you want to redesign the homescreen and make it more beautiful, but not lose all your users and have to make an app from scratch. I’m definitely going go over ten minutes if I don’t speed it up.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*c8HHGbqMv7HzfELRgjZdew.png" /></figure><p>So these are the high-level statistics. We launched beta at Mobile World Congress in February this year and since then we’ve seen over 200 million people using apps that are built with Flutter. You can read the other numbers but we have thousands of apps and the popularity has continued to grow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qu7N1FRFr9X3BuMNpnjogw.png" /></figure><p>So the rest of the keynote we structured in four ways which is the process of building an application, you go from the design to the release. So with the design, and this is something that Will covered live on stage but a lot of people basically talked about when you get an app from a designer and you have to actually develop it, what happens, right? I’m sure a lot of friendships have been lost in this process. What happens is the designer gives you an app like this and you end up shipping an app like that.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*QgJXHzkCjk2tOojTdTjDHQ.png" /></figure><p>And it looks kind of similar but you can look at the top navigation, you can see some of the scrolling and the popups, it’s just easier to use certain parts that are provided by the OEM or other things that aren’t widgets or custom-made properties. So that’s some we really want to fix and achieve something like this. So, like I mentioned a lot of people still do want to have that iOS and Android look and feel so you can specify differences on purpose if you don’t want to have just one branded experience but still want that platform-specific look.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*t6JnX-G_tbBszkK8rRmMMw.png" /></figure><p>Another thing that was announced that people got very excited about was <a href="https://www.2dimensions.com/about-flare">Flare</a>. Flare is a third-party integration from an agency called 2Dimensions. There were two twins on stage and one was a developer and one was a designer, they were identical. Basically they were saying how do you coordinate between those two, and they launched this animations platform that’s free for everyone to use and you can build these beautiful animations and then with one line of code have them appear on Flutter. And I don’t have it on here and I’m definitely going to go over 10 minutes, but the cool part about their demo was you could move this person up and down and their skeletal structure will stay the same. And you can also have all these other custom things that if you catch the keynote you’ll definitely be able to see their demo here.</p><p>The second part was develop. So once you design the app you have to develop, right? Coding should be fun. I’m pretty sure this circled through other words but this is the one that we’re stuck with but it’s true, it should be very fun. So we showed a live coding demo during this part of the keynote and we also announced <a href="https://medium.com/dartlang/announcing-dart-2-1-improved-performance-usability-9f55fca6f31a">Dart 2.1</a>. Dart is the language that powers Flutter. It wasn’t as popular and now it’s becoming very popular and the great thing about Dart, besides the fact that it compiles ahead of time and has a lot of things that make Flutter the way it is, is that Dart is really intuitive to learn. On the home page of the new design website we worked on we added Flutter for iOS developers, Android developers, web developers, React Native developers, all sorts of things because we realized that Flutter should not be something as a developer that you’re putting things aside to learn Flutter. It should be in addition to your toolkit. So you don’t have to give up your identity as an iOS developer or as an Android developer or as a web developer. Dart is just like an object-oriented language you can just learn on top of those other languages and still maintain those identities. And that’s something we want to stress with the team, we don’t want you to drink this Flutter kool-aid, hop on the Flutter train, and never hear about anything else, right? But we made it really easy with documentation to make that transition if you’re already familiar with a certain language to learn Dart. I saw someone tweet the other day saying they’re not hiring for Dart developers because it’s just very quick to learn, so if you know how to code you should be fine.</p><p>The third is connect. So we mentioned about the open source and all the packages. Square also launched a couple of things, a reader SDK and an in-app payments SDK for Flutter to really easily integrate and hopefully make money off your apps because I assume not all of your making apps just for fun. So this is a really useful tool.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*B9ICeAbukUvC9WQ6KXQhJg.png" /></figure><p>And then finally release. Tim showed this picture on stage. I saw him on this the day before the keynote and I was like Tim are you doing, you should be practicing, but now I know why. He wanted to demonstrate what CI/CD, or basically releasing your app is like nowadays. Because you have the app ready, and you’re like alright great, all I have to do is the APK, the IPA release it on both stores, and I’ll be done. Yeah right. You have to get all the screenshots, you have to basically making the app ready, it’s a whole process to release the app. So luckily we have a partnership with <a href="https://nevercode.io/">Nevercode</a>, and they launched <a href="https://codemagic.io/">CodeMagic</a> and this is also a third-party integration with Flutter that allows you, once you build the app, to actually ship it really quickly to both iOS and Android stores. Obviously Flutter being for both it’s a really good tool and you can also use it just for one of them and it still makes it a lot easier.</p><p>And finally, beyond mobile. When I joined the Flutter team the value proposition was make it easy to build mobile apps. But the team at the time when I joined said yeah but long term that’s not our vision. The title of this presentation is not building beautiful mobile apps, it’s Google’s portable UI toolkit. UI toolkit because we want Flutter to run on all screens, not just moboie. If you think about your day, we have screens everywhere. We have screens in cars, we have screens on watches, we have screens on phones, but as developer you literally have to adjust at every platform, and that’s so frustrating. Obviously we’re trying to solve the iOS and Android problem first but eventually you should just be able to focus on what you love which is building the application, the design, and have that work on the screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*k6GUNf9Hz8G-LsNY78AqVA.png" /></figure><p>So we talked about <a href="https://github.com/google/flutter-desktop-embedding">Flutter Desktop Embedding</a>. This was the mind-blowing moment of the keynote I heard from the New York people, as soon as we said the whole presentation, not mine, I didn’t have time to do it, but the whole Flutter presentation at 1.0 was running on a Flutter app, so we weren’t using Google Slides, we weren’t using PowerPoint, the whole thing was built off of Flutter. So we kind of exited out and showed that, and then we previewed something called Hummingbird. This is where a lot of the excitement is as well, which is Flutter running on web. I mentioned earlier that unlike some of the third-party cross platform toolkits, Flutter the way it works, is it compiles directly to native ARM code, native machine code. But with Hummingbird, it compiles to JavaScript, so you’re able to write Dart and Flutter for the web. I’m sure they’ll be questions about this, so I’ll skip it.</p><p>I’m done. I’m not sure if that was 10 minutes. Learnings for next time. I should’ve done a countdown clock like Emily Fortuna and Matt Sullivan. On the flight here I was watching Mission Impossible, and Tom Cruise stops the detonation a second before, and I’m like, that’s Emily on stage. Literally, a second before she’s like, boom, the app worked and then the time was up, it was unbelievable, I was sweating.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*Lt9mmaKK5eFIqluNnn_vBw.png" /></figure><p>Ok, technical overview. So, sometimes it’s helpful to visualize how Flutter works. So basically the way Flutter is built is that we have this underlying engine that’s powered by <a href="https://skia.org/">Skia</a>, this graphics engine, and Dart. And everything in green and everything else is the framework and that’s what you as a developer have full control over. So you basically can go all the way down in the code, but obviously not a lot of people have a lot of time so what we do is we provide all these widgets. Everything in Flutter is a widget. Which means instead of starting from scratch, if you want to add scrolling or navigation, even if it’s custom you can start with one of our widgets and then start customizing that. Makes a lot of sense. But the good news is if you’re really really really picky and nothing has been created before, you can go down and actually make something custom. Not only that, but you can also upload it, have other people use it, they’ll become your best friends, you’ll grow your Twitter following, it will be great. So that’s a Flutter overview. What I want to do now is bring up Will Larche. Will is our head of design, he spoke at the event, he’s going to now talk a little bit about the demos that you saw at Flutter Live, and how he built them.</p><p><a href="https://medium.com/u/790460f492fa">Will Larche</a>: First, I’m going to apologize, I’m kind of a little hoarse from the after-party. It was crazy, in this pizza place that had karaoke and seven-foot ceilings, and all these people having a really good time, and it was nuts and we said like this is always like this, on a Tuesday? And the waitress goes, “no…” So we don’t even know why it was so crazy. I also wanted to thank <a href="https://medium.com/u/a53992d973c9">Martin Rybak</a> and <a href="https://medium.com/u/6cb0ee65d029">Nitya Narasimhan</a> who’s not here, for arranging the viewing party that we had in New York at the Google office. I couldn’t be up but my team, Anthony Robledo and MH Johnson also helped out. It seemed like it was a lot of fun, and I’m glad we were able to do that even though I wasn’t going to be here.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*9p6P9rRCCwsXy4AKYTKUEw.png" /></figure><p>So, I want to talk about the studies that I showed during the design segment of the talk. Who am I? I’m Will, the Flutter Engineering Lead at Google, in the <a href="https://material.io/">Material Design Department</a>. Most people forget that we have actually more engineers than designers in Material Design. We have them on web, iOS, Android, and then last year I added Flutter to that. And my team works in partnership with Flutter on all things really having to do with design engineering for Flutter directly, as well as supporting the apps inside Google that are built with Flutter.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*ghFqXg2uU5QEH5a23aVTgg.png" /></figure><p>So, almost all the examples that I showed during my session come from the Material Guidelines section on studies. What are these? These are hypothetical products that our designers use to stress-test the design guidelines that we have and also see what opportunities there are to extend the components to other places and practice naming and branding. You can get to it at that website that’s up there or you can just go to <a href="https://material.io/">material.io</a>, you’ll be able to find it in the navigation.</p><p>One of the things that we wanted to make really special at the Flutter Live event was that I was going out to show a lot of all these animated gifs and I wanted them to be backed up by real code so that you call could go look at it later and have really rich examples of how you use material components in so many different ways for all these different actual cases. And it turns out that we ended up having six and then a couple of tiny examples on the sides. And why is this important? Because this is how you can practice your Flutter. So, I don’t imagine that every single person that’s in this room is actually working at a job where Flutter is what you’re doing all day yet, but you probably want to spend more time learning and practicing Flutter. We create these studies and put their requirements up for them inside material.io so that you could go make one of these.</p><p>I like the guy that I brought up during the design session, Jacob Christensen from <a href="https://material.io/">Reflectly</a>. One of his Flutter engineers practiced Flutter by building one of our apps called Reply and then that was enough skill for him to end up getting a full-time Flutter job. But, he didn’t have an idea an idea of his own to build out an app, and sometimes that can be intimidating when somebody says something like, oh yeah just build an app, and you’re like, on what? That’s not very helpful. Also I don’t have a designer and really I should be practicing what it’s like to work with good designs if I’m going to be learning something. So these are really good places to do that. We’re going to be sending out a blog post with more information about them, publishing all the code for them online so that you can interact with them, but then we’ll leave them all unfinished and that’s a great place for you in the community to submit code and practice PR’s and have code review from us and expand the examples to include the other sections that the designers made that we haven’t had a chance to create. And all of these are studies that I used in the Keynote.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*194c6LZYPwj1-X3m9FcgYg.png" /></figure><p>So the most complete studies that we have are Shrine, which you may have seen from a bunch of other things, or code labs; Rally, which was built by Anthony here and how many days did you have to build the first version of this? Three? Anthony did it in a hackathon and it was like one of the best things in it, it got my highest vote from all the things, and it shows a lot of cool stuff, like how do you deal with those kinds of graphs, and that custom navigation; and then the last one is Crane, which was built with an intern of mine and then a few people including MH who’s not here, which shows a lot of custom things, including the tab bars and the backdrop components, and the choreography between them. So animation, I’ll be honest, in Flutter, is a little bit difficult to learn. There’s a learning curve for it. One of the reasons why it’s like that is because it’s so crazy powerful. It is far more powerful and finely tunable then what I’m used to coming from iOS, and I was a Core Animation expert, so I know what it’s like to get to the lowest level that I can get you before and I’m going to <a href="https://www.opengl.org/">OpenGL</a>. And this is another layer lower really, there’s so many things that you can do by saying how you want things to be interpreted or lerped without having to create individual keyframes. So you should look at how we’re doing animations in there as examples because there’s often many different ways to do something in a framework as big as Flutter and it’s good to know all of them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*dapj9yx4dmTT97Bd-dMa1Q.png" /></figure><p>So they also showed some custom drawing. Rally has a graph in it that you see right there. I never practiced drawing a chart like that and so now Anthony’s given us some code that we can use to do that. All of these are just super custom, so they don’t look like that kind of cookie cutter Material Design app that you get. These have all been branded and expressed through a company’s brand guidelines, which is something that you will do on your regular job, and if you’ve practiced doing that, that could be really useful once you begin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*-fu3qJH022KAeRlc7509Ug.png" /></figure><p>Then we had three that were focused on a single partner. This one is Basil and I’ll be honest with you, I misspelled spinach the first time I made this, and that was what was in our backup deck, so if the app that we had made for some reason wasn’t working we were going to go to slides and then the entire world would have seen that I can’t spell spinach. So, I’m so glad there were no problems with that. But then, I saw someone on Reddit today spell it just S-P-I-C-H, which is just “spinch.”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*ZQEoAfTgBh4wegyQpuM7aw.png" /></figure><p>This one was to show off typography. The kind of letter spacing and word spacing control that we have in the <a href="http://flutter textstyle bold">TextStyle</a> object instead of buried down in <a href="https://developer.apple.com/documentation/coretext?language=objc">Core Text</a>. That’s something that I’m not used to being able to do easily coming from iOS dealing with <a href="https://developer.apple.com/documentation/coretext?language=objc">attributed strings</a>. Again, they are a really great data type that can store a lot of information, but they are not too easy to create. They are not easy to make complicated, and also when it comes to letter spacing I don’t even think that’s something that’s in attributed strings, I believe you do have to drop down to Core Text for that, and that’s nuts because that’s really hard. And you would be like, well it’s just not worth it for that label. But maybe now you don’t have to say well it’s just not worth it, you can just say we’ll just do it. [<strong>correction</strong>: Attributed strings have kerning. It was word spacing I was thinking of. You’d have to do that manually in Core Text.]</p><p>Another example that we had up for typography was Fortnightly which is a hypothetical newspaper out. This one, it’s just really pretty. I don’t think that the thing else except proove that we can have print-quality typography in Flutter. A lot of people assume when you’re going to be using a tool like this, that you’re going to have to make a lot of compromises and then you’ll get some crappy results, and that’s not the case for Flutter. Because I would just assume that that was just made in…well if I’m not mistake the New York Times used to make all of their stuff directly in OpenGL so they could have complete control over what’s going on with the typography, which is weird because OpenGL isn’t exactly made for typography, and so I would have assumed that maybe somebody went through a lot of trouble on that for this. Didn’t, made it in two minutes!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*wT4NwbS6tNsYeKrYBYnJoA.png" /></figure><p>This one was one that I’m also showing because I made it so quickly. Aside from the presentation of that thing which we call the Extended Bottom Sheet which I borrowed some code that was not made for this example but made for the Shrine example, I made this in less than half an hour kind of in emergency style on the 4 train on my way to work with a lot of distractions and stuff. I’ve never been able to make something that I could put it into a televised-to-thousands-of-people example that quickly and never have to go back to it again. There’s no polish that I had to do for that to express what I needed it to do here. It’s also a good example for teaching how to deal with <a href="https://docs.flutter.io/flutter/widgets/SafeArea-class.html">Safe Areas</a> which are for avoiding things like the notch at the top or the home bar on an iPhone and how to do that in Flutter.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*4BlI-tuoRYTBYuqfDO48pg.png" /></figure><p>And then again, this is Anthony’s charts here. And drawing something like that is something that can be very, very intimidating. You know, like everybody’s just like oh it’s a line, it’s just a chart or whatever, but until you’ve practiced that sort of thing it seems like this could either be easy or this could be so hard that I’ll never get it done in time and I should ask them to just do something else or bring in a package like some sort of charts package and just bring it in. Which is also fine if that’s what you need to do, but it’s also a really valuable skill to be able to do custom drawing like that.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*_m8LLGevZ25vQ_O62Nz-uQ.png" /></figure><p>And then we had another one that was made by Andrew Brogdon and his intern out in Mountain View to specifically show Cupertino in action. So this is a Veggies app, it lets you know what’s in season, and you get to say things that’s what’s going on there, search, but this you can see, the aesthetic is expressing Apple’s iOS design language which is an official term that I found inside Apple’s documentation…once. They only describe that they do this…once. See you can look at those switches are iOS switches, they don’t look like Android switches. All this stuff, I think it looks like the sort of thing that could’ve just come right from Apple themselves. And so like I said, we’re working on a blog post right now where we’ll have really good distribution for you all. Hopefully these are going to get into the actual Flutter gallery which is an app that you can build and compile and run when you get the Flutter project cloned to your computer. In the meanwhile, almost all of this is already on our repo which is <a href="https://github.com/material-components/material-components-flutter-experimental">Material Components Flutter Experimental</a>. I’m going to do a push once I get home because I forgot on my other computer to put even more of them up there, so while those aren’t totally done yet, you can still go look at them and see real live how we made them. It’s just the whole point, oh and that was it for my stuff, ok thanks!</p><p><a href="https://medium.com/u/984284ef4c17">Martin Aguinis</a>: Thank you Will. It’s crazy, I once saw an open-source project — someone made an app that looks like iOS for Android devices and Android for iOS devices and it was freaking everyone out, because you have an iPhone and it’s seeing doing all the Android behaviors, and that shows the flexibility of Flutter.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*jThh0Ux7rOFp2dLPQj_qOA.png" /></figure><p>So I wanted to talk about Hummingbird a little more. We briefly mentioned it in the keynote, but there is a blog post out there that has more of these details, but it’s really interesting because the blog post details as the Flutter team what were the things we were thinking of and we’re making Flutter for the web? And these are the three approaches we had to build Hummingbird. The first one was just widgets, so basically using all the web capabilities but building it just in widgets. The second one was some widgets and custom layout, so as you see provided by the <a href="https://docs.flutter.io/flutter/rendering/RenderObject-class.html">RenderObject</a> we have some HTML elements. And then finally the one we ended up choosing was Flutter Web Engine, which would have a Dart UI underlying engine in that blue area you saw earlier where you didn’t have control over, but then everything else would be a widget so you have full control that would render to JavaScript and that’s what we ended up doing. So this is kind of that same diagram you saw earlier tech-wise for Flutter for mobile, but for web you can see that bottom one would be the Flutter Web Engine, and the top is is everything you have control over. And I really encourage you to visit our blog post especially if you are interested. Obviously we say we’re only previewing this, this isn’t something that we say is widely available right now, go build for web, but I know people are really interested in it, so I did want to provide a little bit more context there.</p><p><a href="https://medium.com/u/790460f492fa">Will Larche</a>: So I’ll talk about this. And actually if I can go back to that last thing, I have a hard time kind of understanding what those one two and three options were. Obviously the only one that matters is three because that’s what we went with, but I think what they’re trying to express is that they tried, can we just replace the widgets later with web stuff, what does that look like, all the layout still happening by the <a href="https://en.wikipedia.org/wiki/Document_Object_Model">DOM</a>, it’s all browser style. Well, layouts may be not working so well, let’s try replacing the rendering layer with our stuff and then they were like, hey how about we go all the way down because that seems to be the only way that we can get these to work the way people were really expecting them to? And what does that mean?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*JRl1gwzeMxjxy0tqt7FIBQ.png" /></figure><p>So this is a hypothetical tree that could happen if your app had these widgets and stuff where you can see the green boxes are things that come rather than regular HTML and CSS, they’re dealing with the DOM and we’ve taken our widgets and converted them into regular objects that way. That’s what we want to do as much as possible. When you’re dealing with widgets that have text in them, wouldn’t it be really great if they just worked the way the web span, div or whatever works or something that had some text in it. If we can get that to work, that’s great. If you need to do something that goes beyond that, then we switch to drawing directly onto the canvas, which is a little more complicated because it’s a bitmap, and you can read in the blog post on Medium.com definitely some more details on that. This is all subject to change by the way because this is experimental and it’s in the lab and it’s not something that we’re working on in the open yet until we’ve totally decided what we’re going to do. I say “we” like I’m working on this; I have nothing to do with this. I’m just really freaking excited about it and when I saw this I was like, oh, I think I bet on the right horse here, so yeah.</p><p><a href="https://medium.com/u/984284ef4c17">Martin Aguinis</a>: Thanks Will. Great, so it’s funny, when I joined the team, I had to bet all of my marketing energy toone app, which was the Hamilton broadway musical. So any time I would go somewhere I’d be like, yeah, Hamilton uses it. We use it a lot within Google as well, but now it really really has turned and it’s no longer obviously a beta product, and that’s very indicative also in terms of who’s using it. So we created this really cool asset, this video that we showed, and I’m going to show it now, which kind of highlights some of the apps since the beta launch this past February that have been built with Flutter.</p><p>So we’ll share a little bit more about other apps that have been built, but we have the privileged to have Clay Elliot with us today. Clay has made an app with Flutter and it’s always great to hear first-hand from from some of those experiences, so without further ado, welcome Clay!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*wnkCnBTXwzGvlBGkjvWQjw.png" /></figure><p><strong>Clay Elliot:</strong> Thanks. Hey guys, I’m Clay. I’m not a developer, I’m usually on the business side of startups and this is my contact info. I know we’re a little short on time so if any of you non-developers need help navigating the space, feel free to reach out. But what I wanted to show you was the performance of the app in real time, I just screen recorded it right before I came down here, and it is really snappy. So I started with Ionic and WordPress and I was pretty happy. The app performance was okay, but the features, what I could do with it, was just not as good as what you could do with native. So I tried out Flutter and I moved to Firebase as well, and not only did I get the performance, but build it once and I got my iOS app out of the same codebase. And not only that, because in Ionic you also build it once and then it goes to both codebases, but more code worked when you built it in Flutter, like every time. And the other thing is the the hot reload. When you’re dealing with different time zones, it is so valuable to just have that, not send you a build and then go to sleep and have to wait for hours. So that was a lifesaver for me, I know that not going to be the same for every situation but I can’t say enough about the hot reload.</p><p>So it’s in preview right now, it’s called TicTic Bucket List, but it works like Tinder. You can pick places that you want to go, you say yes I did that or I’ve already done that, or I’m not interested in that. So any questions from from the business side that I can answer real quick? How do you make money? So just like Tinder there’ll be some interstitial ads and then as well when you flip that card over, it is a description of the place and so I can send a person off to to Wikipedia or send them to a place to book that cruise. Were you at full release under Ionic and then how long did it take you to roll over? I started from scratch and I was in beta with Ionic, and it probably took me about 2 months to just rebuild it from scratch. I saved a little bit of time because I had the designs basically but the app to be built in Ionic, even that took three and a half months, so saved 30–40% of time. Alright I think we have to move on. Thanks guys, sorry I couldn’t show you the video, but come on the 17th of January and I’ll show you the whole thing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*xX3-OeYMEne1kJVIQhVIvg.png" /></figure><p><a href="https://medium.com/u/984284ef4c17">Martin Aguinis</a>: So I mentioned Hamilton, that was one of the first big wins. They took a huge bet. The team was like, you know Hamilton himself, young scrappy and hungry, he took his shot, so we’re going to take one with Flutter. We were definitely in alpha very early on but they took a bet with us and it worked. They had three months to launch this app, because that’s when their touring show was starting, and that was really hard deadline. Not only did they get it out in three months but it was featured on both the iOS and Google Play stores. The app got over a million installs, but more impressive to me is that it’s over half a million monthly active users, which means that over half a million people are going on this app monthly, which shows the retention levels, that people are happy with the app. Because you get a lot of users by paying for a lot of ads, but the retention is really important. I won’t show it now but we have a really cool case study video with the Hamilton team about this, so if you look up Hamilton Flutter you’ll find it and I think it’s great. And if you look at the pre-show for Flutter Live I did rap a little bit of Hamilton in there at some points, and someone tweeted Martin you’re a rap God, I’m like alright let’s not go that far, that was pretty bad. But the pre-show had some also interesting content with interviews from the Flutter team.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*xm9WFFpeQOaFXxJxVNf5cQ.png" /></figure><p>The second one was Google Ads. So we as Google have large internal bets on Flutter. All of our ads system is built with Dart and our ads app is built on Flutter and that powers hundreds of billions of dollars for Google. So when people said oh is this an experimental project, we say, ads. Google has some big bets on that. We also have, and I won’t show it now because again we don’t have much time, but we have an Alibaba case study video as well where you can see how Alibaba used Flutter to power parts of their app with over 50 million downloads. So millions of devices.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*j7KROgIlGXx58GnBwIBkkg.png" /></figure><p>Will brought up <a href="https://reflectly.app/">Reflectly</a> during the keynote. They are a really cool app on meditation that was featured as a top 10 meditation app on iOS. It was really great, and they have an iOS look and feel which shows that perfectly. And finally we talked about how we have you covered. Clay just mentioned the interstitials or ads. We have a lot of plugins and ways to integrate Firebase and cloud but also a lot of things as I mentioned, it’s very open, but also a partnership. So we feedback from the community and we’re very reachable. One of the biggest things we get complimented on as the Flutter team is how open we are and how quick we are to listen to your feedback and answer your questions. And also the community so responsive. I was building a Flutter app so I made an alias and I had a question so I asked, and of course they didn’t know I was on the team, and within 30 seconds someone on Gitter chat answered and then DM’d me and said, “Hey, I love Flutter, what do you think about it?” That’s pretty cool! And I don’t get that in many other communities, so anyway that was really really cool.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*-NHke2q4uUV5IwfUpR0jvg.png" /></figure><p>And then finally I want to end with this, which is that there’s four different ways you can get started with your Flutter app. A lot of people think, oh I have to have an app idea to start with Flutter. That’s not true. The first way though is obviously starting an a from scratch. So if you want to go with a brand new app you can build with Flutter on one code base and it will run natively on iOS and Android.</p><p>The second way is prototyping a new idea. Let’s say you just have a concept in mind and you don’t care too much about design yet or you want to design just a part of it, can quickly build it out in Flutter, test it out, see what happens, and then pivot building your MVP.</p><p>The third is bringing your app to the other platform. So you already have an iOS app built, or already have an Android app. You can build for the other one, and eventually merge the codebases. That’s something that <a href="https://itunes.apple.com/us/app/topline/id1270125833?mt=8">Topline</a> from Abbey Road Studios did. We actually opened up the Flutter Live event with that video; that’s another case study you can check out. They made a music recording app and they already had an iOS app, and they made their Android really really quickly with Flutter and now they’re integrating both. And what’s nice about that is once you launch the app, it’s just the beginning because every time you want to do an update to the app or launch a new feature you have to synchronize the releases. You’re going to have to do the do the same thing on both platforms, sometimes one takes longer to improve than the other, so those half of your users are not happy and they think you’re A/B testing things and you’re not, it’s just because you couldn’t release it. So with Flutter obviously eventually merging it’s really really easy.</p><p>And then finally, using Flutter for part of your app. And that’s something that Alibaba did for the <a href="http://Xianyu app">Xianyu</a> app which is like their eBay. Millions of people use this app to buy and sell things in China and other parts of the world. And what they did is they realized that their item detail page and a few other parts of the app weren’t beautiful and they weren’t working very well so they just wrote those parts in Flutter, put it into their already existing app, they didn’t lose any of their users, and it was a pretty flawless transition. Funny story I’ll end with which you wouldn’t hear at the keynote, but we as Google have another internal app that was built natively. And this was the beginning of Flutter and they decided to rebuild in a Flutter and relaunch i, and to this day users have no idea it’s a Flutter app. Because that transition, it still looks exactly the same, so I thought that was pretty powerful. So thank you so much for being here and we’ll take a few questions and we’ll stick around at the bar!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=428df6a5b664" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-nyc/flutter-live-18-recap-with-martin-aguinis-428df6a5b664">Flutter Live ’18 Recap with Martin Aguinis</a> was originally published in <a href="https://medium.com/flutter-nyc">Flutter NYC</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Mock Singletons and Static Methods in Unit Tests]]></title>
            <link>https://medium.com/@martinrybak/how-to-mock-singletons-and-static-methods-in-unit-tests-cbe915933c7d?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/cbe915933c7d</guid>
            <category><![CDATA[unit-testing]]></category>
            <category><![CDATA[mocking]]></category>
            <category><![CDATA[dotnet]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Thu, 31 May 2018 19:30:55 GMT</pubDate>
            <atom:updated>2019-09-16T22:16:24.390Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/980/1*1MaN_0viE0yiJS7dgI4FOg.jpeg" /></figure><p>So you’ve had enough. That aging codebase of yours is just too darn fragile to work on. Everytime you fix a bug or add a new feature, something unexpected breaks. Your manual test plans aren’t thorough enough to catch these regressions, so the only way you find out about them is through angry customers. By the time your support team hears about them and they are triaged, groomed, prioritized, entered into a sprint, and finally fixed, it could be weeks. Not a great recipe for a successful product.</p><p>You already know that automated unit tests guard against regressions by constantly testing your code at the lowest level, but your legacy codebase is a mess of singletons and static method calls that are impossible to mock. <em>Or are they</em>? Here are some techniques you can use to make that code testable without making drastic (and risky) changes. The examples shown are written in C# but the concepts should apply to any object-oriented language.</p><h3>Mocking Singletons</h3><p>Here is an example of C# code that calls out to a singleton. How can we write a unit test that verifies that calling Bar() actually invokes DoIt()?</p><pre>public class Foo<br>{<br>  public void Bar()<br>  {<br>    Helper.Instance().DoIt();<br>  }<br>}</pre><blockquote>We assume that <em>Helper</em> implements the <em>IHelper</em> interface. If it does not, and the class is not modifiable, use the technique shown in the <strong>Mocking Static Methods</strong> section below.</blockquote><p>Let’s create a private member variable to hold onto an instance of IHelper, and a constructor that sets that variable. This is known as the <a href="https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection">constructor</a> form of dependency injection. We will use this constructor in our unit tests to inject a mock version of IHelper and verify that DoIt() was called. However, the trick to not breaking the current implementation is to <strong>also provide a default constructor that gets its value from the existing singleton</strong>.</p><pre>public class Foo<br>{<br>  private readonly IHelper _helper;</pre><pre><strong>  public Foo()<br>  {<br>    _helper = Helper.Instance();<br>  }</strong></pre><pre>  public Foo(IHelper helper)<br>  {<br>    _helper = helper;<br>  }</pre><pre>  public void Bar()<br>  {<br>    _helper.DoIt();<br>  }<br>}</pre><p>We can use <a href="http://www.csharp411.com/constructor-chaining/">constructor chaining</a> to avoid duplicating code:</p><pre>public Foo() : this(Helper.Instance())<br>{<br>}</pre><p>Now your code is testable, but perfectly backwards-compatible! Here is what a unit test would look like using <a href="http://xunit.github.io/">Xunit</a> as the test runner and <a href="https://github.com/moq/moq4">Moq</a> as the mocking framework:</p><pre>using Xunit;<br>using Moq;</pre><pre>public class FooTests<br>{<br>    [Fact]<br>    public void Bar_Invokes_Helper()<br>    {<br>        var mock = new Mock&lt;IHelper&gt;();<br>        mock.Setup(x =&gt; x.DoIt());<br>        var foo = new Foo(mock.Object);<br>        foo.Bar();<br>        mock.VerifyAll();<br>    }<br>}</pre><h3>Mocking Static Methods</h3><p>Free tools like Moq can only mock interfaces or virtual/abstract methods on classes with a public default constructor. If you need to truly mock static methods, you need to use a commercial tool like <a href="https://docs.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes">Microsoft Fakes</a> (part of <a href="https://www.visualstudio.com/vs/enterprise/">Visual Studio Enterprise</a>) or <a href="https://www.typemock.com/isolator-product-page/">Typemock Isolator</a>. Or, you can simply create a new class to wrap the static method calls, which <em>itself</em> can be mocked.</p><blockquote>Languages differ in this regard. Java developers can use <a href="https://github.com/powermock/powermock/wiki/Mockito">PowerMock</a>. In Objective-C, static methods, a.k.a <a href="https://www.techotopia.com/index.php/Writing_Objective-C_Class_Methods">class methods</a>, can be mocked using <a href="http://ocmock.org/">OCMock</a>.</blockquote><p>Here is an example of code that calls a static method on the Helper class:</p><pre>public class Foo<br>{<br>  public void Bar()<br>  {<br>    Helper.DoIt();<br>  }<br>}</pre><p>Let’s create a new class called HelperWrapper that implements IHelper and wraps the static method call:</p><pre>public class HelperWrapper : IHelper<br>{<br>  public void DoIt()<br>  {<br>    Helper.DoIt();<br>  }<br>}</pre><p>Back in Foo, we create a constructor that accepts an IHelper instance for testing, and a default constructor that creates a new instance of HelperWrapper. (Ideally, you would use a <a href="https://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx">DI container</a> for this). Your class is now testable, and nothing is broken in your calling code.</p><pre>public class Foo<br>{<br>  private readonly IHelper _helper;</pre><pre>  public Foo() : this(new HelperWrapper())<br>  {<br>  }</pre><pre>  public Foo(IHelper helper)<br>  {<br>    _helper = helper;<br>  }</pre><pre>  public void Bar()<br>  {<br>    _helper.DoIt();<br>  }<br>}</pre><h3>Testing Your Own Static Methods</h3><p>What if you want to write a test for one of your own static methods, which itself calls out to other static methods?</p><pre>public static class Foo<br>{<br>  public static void Bar()<br>  {<br>    Helper.DoIt();<br>  }<br>}</pre><p>In this case, we can create an overload of the method under test that accepts an IHelperWrapper, and use the original method to create a concrete HelperWrapper to pass into that method. This technique is called the <a href="http://coders-kitchen.com/2015/05/24/dependency-injection-method-call/">method call</a> form of dependency injection.</p><pre>public static class Foo<br>{<br>  public static void Bar()<br>  {<br>    Bar(new HelperWrapper());<br>  }</pre><pre>  public static void Bar(IHelper helper)<br>  {<br>    helper.DoIt();<br>  }<br>}</pre><p>And here is the corresponding unit test:</p><pre>using Xunit;<br>using Moq;</pre><pre>public class FooTests<br>{<br>    [Fact]<br>    public void Bar_Invokes_Helper()<br>    {<br>        var mock = new Mock&lt;IHelper&gt;();<br>        mock.Setup(x =&gt; x.DoIt());<br>        Foo.Bar(mock.Object);<br>        mock.VerifyAll();<br>    }<br>}</pre><p>Hopefully these techniques have given you some inspiration for tackling what can seem like an untestable legacy codebase. Using them, your team can start writing some tests to verify critical functionality without a drastic rewrite of your application. Remember though, that unit tests are only valuable if they are actually run. The best way is to use a build server to require a successful build and passing unit tests as a precondition for merging a code branch. Good luck!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cbe915933c7d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Things to Remember Before Shipping Version 1.0 of your Mobile App]]></title>
            <link>https://medium.com/@martinrybak/5-things-to-remember-before-shipping-version-1-0-of-your-mobile-app-5a1676f0fdbf?source=rss-a53992d973c9------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a1676f0fdbf</guid>
            <category><![CDATA[api-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Martin Rybak]]></dc:creator>
            <pubDate>Tue, 13 Feb 2018 18:50:57 GMT</pubDate>
            <atom:updated>2018-02-14T15:16:50.969Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*zAcRmv8ODzLmgTakXVYtDg.jpeg" /><figcaption>Developers launching an app.</figcaption></figure><p>A mobile app is a great way to build a premium user experience, but it comes at a cost. One of those costs is permanence. Unlike a web app which can be updated at any time, mobile apps, once published, are out there forever. Knowing this, here are a few tips I’ve learned over my career and which I encourage you to implement as early as in your initial 1.0 release.</p><h3>1. Version your API</h3><p>If your app accesses a server API, its URL will be baked into your app. In order to add or update features, this API will need to change over time. Ideally, these changes should be as backwards-compatible as possible, but at some point you will want to make a breaking change. Not a problem…as long as you version your API. There are <a href="https://www.xmatters.com/integrations/blog-four-rest-api-versioning-strategies/">many different techniques</a> for doing this, but the most common is to put the version number in the URL path, such as:</p><pre>https://api.example.com/<strong>v1</strong>/products<br>https://api.example.com/<strong>v2</strong>/products</pre><p>Now you can support older app versions concurrently with newer versions. However, there will still come a time when you won’t want to support multiple versions of your API. In that case, you need to…</p><h3>2. Add a kill switch</h3><p>Once a user installs your app, there is no guaranteed way for you to update it on their device. While both the Apple and Google Play stores offer auto-update by default, there is no strict timeframe for this to occur, and it can even be disabled by users. This means that, at any given time, multiple versions of your app will be in the wild. Eventually, you will want to deprecate an older version. Perhaps you’ve made a breaking change or fixed a critical bug. In that case, you need a way for the app to know it has been deprecated, and present a friendly upgrade message to the user.</p><p>A graceful way to handle this is to have your API server return a special status code, such as <strong>301</strong> (Moved Permanently) or <strong>410</strong> (Gone), for any requests made by deprecated versions of your app. When your app receives this status code, it should present a dialog reminding users to update, while entering read-only mode. Remember, you should still keep the app as usable as possible by allowing read-only access to any cached or local data stored on the device.</p><p>How does the server know which request is coming from a deprecated app version? If you use API versioning,you can simply make a particular API endpoint always return the special status code. However, a more granular approach is for your app to identify its platform, OS version, and app version in the User-Agent header of each HTTP request. It is up to you to come up with a format that contains what you need. For example:</p><pre><strong>User-Agent: MyApp/1.0.0(31) iOS/10.3</strong><br>              |     |   |    |    |<br>           app name | build  |    os<br>                 version  platform</pre><p>When your server sees a request come in from a deprecated version, it should return the special status code. Even if you’re not using it on the server yet, I highly suggest to bake these host headers in as early as the initial 1.0 release of your app.</p><h3>3. Log a user out remotely</h3><p>There will come a time when a user’s account or permissions change, and you will need to log them out of the app remotely. You may even want to go as far as purge the data on the device if it belongs to a terminated employee, for example. In these cases, your API should return a special status code such as <strong>401</strong> (Unauthorized) or <strong>403</strong> (Forbidden) that the app interprets by doing a “soft” logout (sending them to the login screen while retaining the local data on their device) or a “hard” logout (doing the same but deleting all local data). As with anything that destroys data, be careful and test this thoroughly!</p><p>Remember, even with a hard logout, there is nothing stopping a crafty determined employee from putting their phone in airplane mode (preventing the status code from being received), and extracting the data stored in their filesystem for nefarious purposes. Don’t store more than the minimum data that your app needs to function.</p><h3>4. Support impersonating users</h3><p>As soon as your app ships, you will need to support it. Inevitably, a customer will contact you with an issue with their account. Your support staff will understandably ask you if they can log into the app as a particular user. That should normally be impossible because you <a href="http://blog.moertel.com/posts/2006-12-15-never-store-passwords-in-a-database.html">never store unhashed user passwords</a> anywhere, right? <strong>Right??</strong> In that case, you need to build an impersonation mechanism into your app.</p><p>For example, you can create a secure web page where support staff can log in (this is typically your “admin portal”). On that page, support staff are able to look up a registered user and generate a short-lived token…the same token that the user normally receives when they log in (typically a <a href="https://jwt.io/introduction/">JWT</a>). Now you just need to get that token into the app. You can do that by designing the app to accept a <a href="https://coderwall.com/p/mtjaeq/ios-custom-url-scheme">custom URL scheme</a> such as:</p><pre>yourapp://token/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...</pre><p>When your support staff open that link on a device, the app should bypass the login flow and automatically log them in as that user. As with any impersonation tool, be sure to consider the security implications of this technique. Keep in mind industry-specific compliance regulations such as PCI and HIPAA. Be sure to restrict this functionality to certain staff only, generate short-lived tokens if possible, and don’t copy the token around insecurely. Even if you don’t have the admin portal ready on day one, you should at least build the custom URL handler for accepting tokens in the 1.0 version of your app.</p><p>Nowadays there are additional tools that can make your support staff’s lives easier. For example, you can use <a href="https://appetize.io/">Appetize.io</a> to run a real instance of your app inside a web browser (!). It has a free tier and is very flexible and can run different builds on different OS versions and devices. You can use their API to send them a build as part of your deployment pipeline. If you really want to be fancy, you can update that impersonation page in your admin portal so that support staff can select the user, device, OS , and app version, and with a click of a button, be taken to the app, automatically logged in.</p><p>For the next level of support, you can also consider in-app chat and screen sharing tools such as <a href="https://chat.zendesk.com/hc/en-us/articles/213911768-Introducing-the-Mobile-Chat-SDK">Zendesk</a> or <a href="https://integrate.teamviewer.com/en/develop/screen-sharing-sdk/">TeamViewer</a>. Naturally, this has security implications so use this wisely.</p><h3>5. Install crash reporting and analytics tools</h3><p>As soon as your app launches, your product manager will immediately want to know how it is doing. Relying on API server logs only tells you a tiny piece of the story. A free crash reporting tool like <a href="https://try.crashlytics.com/">Crashlytics</a> can keep track of when your app crashes, and point you to the exact line of problematic code. A free analytics tool like <a href="https://developers.google.com/analytics/solutions/mobile">Google Analytics</a> can collect valuable data on what screens users use, as well as device metadata. An APM (Application Performance Monitoring) tool like <a href="https://newrelic.com/mobile-monitoring">NewRelic</a> can tell you what the network latency experience is for your users. If you want to get really fancy, a screen recording tool like <a href="https://www.appsee.com/">AppSee</a> can record heatmaps of your users’ interaction with your app, pointing out UX problems, and providing videos leading up to crashes. Again, the sooner you add these SDK’s to your app, the sooner you can start collecting data.</p><p>Remember, when coming from a web-centric world, mobile apps are a different beast. Once you ship your app, the proverbial cat is out of the bag. To minimize future pain and frustration, it’s best to build in these considerations into the intial 1.0 release of your app. Good luck!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a1676f0fdbf" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>