<?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 Diego Velasquez on Medium]]></title>
        <description><![CDATA[Stories by Diego Velasquez on Medium]]></description>
        <link>https://medium.com/@diegoveloper?source=rss-496732f72ff1------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*eHYvko50wOZ8gdDd-MmcMg.png</url>
            <title>Stories by Diego Velasquez on Medium</title>
            <link>https://medium.com/@diegoveloper?source=rss-496732f72ff1------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 16 Apr 2026 02:36:20 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@diegoveloper/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[Flutter: SliverAppBar with Stretchy Header]]></title>
            <link>https://medium.com/flutter-community/flutter-sliverappbar-with-stretchy-header-9ca04f316ff0?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/9ca04f316ff0</guid>
            <category><![CDATA[stretchy-header-effect]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[flutter-widget]]></category>
            <category><![CDATA[flutter-sliverappbar]]></category>
            <category><![CDATA[mobile]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Wed, 22 Apr 2020 07:19:58 GMT</pubDate>
            <atom:updated>2020-04-25T21:14:06.153Z</atom:updated>
            <content:encoded><![CDATA[<p>Wooo after a long time that I didn’t write, this was because I was busy at work, making videos on the YouTube channel (The Dart Side), helping on StackOverflow (Spanish version)and adding new examples to my <a href="https://github.com/diegoveloper/flutter-samples"><strong>flutter samples repo</strong></a>.</p><p>Have you ever seen widgets with headers that can be stretched when scrolling? this is called the Stretchy widget.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/246/1*flvNaeixx0ovQ_OEeEc9TQ.gif" /><figcaption>stretchy_header package</figcaption></figure><p>A long time ago I made a package that helped to solve that problem, this one is called <a href="https://pub.dev/packages/stretchy_header"><strong>stretchy_header</strong></a>, it allows placing a widget which can be expanded with blur(optional) when scrolling, I also added a trigger that works similar to the <strong>RefreshIndicator</strong> widget.</p><p>But guess what ?, now Flutter already incorporates its own stretchy header inside the <strong>SliverAppBar</strong>, I’m going to show you how it works.</p><p>All we have to do is assign <strong>true </strong>to the <strong>stretch</strong> property which now brings the <a href="https://api.flutter.dev/flutter/material/SliverAppBar-class.html"><strong>SliverAppBar</strong></a> and in <strong>flexibleSpace</strong> we use the <strong>FlexibleSpaceBar</strong> widget, which now also brings a new property called <strong>stretchModes</strong> which indicates the effects it will add when we scroll.</p><p>The modes are:</p><ul><li><strong>StretchMode.zoomBackground</strong> -&gt; The background widget will expand to fill the extra space.</li><li><strong>StretchMode.blurBackground </strong>-&gt; The background will blur using a [ImageFilter.blur] effect.</li><li><strong>StretchMode.fadeTitle</strong> -&gt; The title will fade away as the user over-scrolls.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/962/1*plgAV1EgWhl2b-mmnjJgAQ.png" /></figure><p>Here the example using StretchMode.zoomBackground</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*i36WTP20PhSksXZ5RahU-g.gif" /></figure><p>Using StretchMode.zoomBackground and StretchMode.blurBackground,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*BYAUNgSfYOLZ7d5Wc77SpA.gif" /></figure><p>Finally using all 3 modes at the same time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*ZSPsHL5dM8i6C_TMLD9Mlg.gif" /></figure><p>Another interesting thing that it brings is that we can launch an action when we scroll our widget. The property we will use will be <strong>onStretchTrigger</strong>, where we can execute any action.</p><p>By default the trigger is called when the scroll exceeds <strong>100.0</strong> pixels but we can override that using the new <strong>stretchTriggerOffset</strong> property.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/962/1*SUi6KTzQiZQUbP5CEXFLig.png" /></figure><p>Playing around with this widget I was able to replicate a design that I found on the web, this is the result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*9nX94YG3uCC9xpbVIPm8cg.gif" /></figure><h3>Conclusion</h3><p>I hope it has helped you in case you want to add this widget in your project. As you can see the Flutter team is working hard implementing a large number of useful widgets but that many of us don’t know, you can review the last example in my repository</p><p><a href="https://github.com/diegoveloper/flutter-samples">diegoveloper/flutter-samples</a></p><p>You can follow me on Twitter</p><p><a href="https://twitter.com/diegoveloper">Diego Velasquez</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9ca04f316ff0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/flutter-sliverappbar-with-stretchy-header-9ca04f316ff0">Flutter: SliverAppBar with Stretchy Header</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter: Increase the power of your AppBar & SliverAppBar]]></title>
            <link>https://medium.com/flutter-community/flutter-increase-the-power-of-your-appbar-sliverappbar-c4f67c4e076f?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/c4f67c4e076f</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[material-design]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[dart]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Fri, 07 Jun 2019 21:15:49 GMT</pubDate>
            <atom:updated>2019-06-08T14:14:52.214Z</atom:updated>
            <content:encoded><![CDATA[<p>In Flutter to create a toolbar we use the well-known <a href="https://api.flutter.dev/flutter/material/AppBar-class.html"><strong>AppBar</strong></a> widget, and when we want a dynamic toolbar that when we slide it shows us content, we use the great widget called <a href="https://api.flutter.dev/flutter/material/SliverAppBar-class.html"><strong>SliverAppBar</strong></a>.</p><p>These Widgets allow us to add a touch of beauty to our application, and without a doubt, doing it in Flutter is very simple.</p><p>I have seen many questions in <em>StackOverflow</em> and <em>Facebook</em> groups about how we can modify the <strong>AppBar</strong> and <strong>SliverAppBar</strong>, modify in the sense of changing the behaviour or design a bit.</p><p>Let’s see these 2 cases.</p><h3>Case 1</h3><p>We want to create an <strong>AppBar</strong> that is not stuck at the top of the screen as we normally do. But we also want our screen to have a <strong>Drawer</strong> (side menu), and that our <strong>AppBar</strong> respond to the event of opening the <strong>Drawer</strong>. That is, we want to create our own <strong>AppBar</strong>, with the dimensions that we want.</p><p>The problem is that as we know, our <strong>AppBar</strong> widget has a default size, and we can not change it. Checking the source code, we see the parameter called <strong>appBar</strong> from the <strong>Scaffold</strong>, we see that it accepts a widget of type <strong>PreferredSizeWidget</strong>, now we review the source code of <strong>AppBar</strong>, and we find that it is only a <strong>StatefulWidget</strong> that implements <strong>PreferredSizeWidget</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*nps2Jnb9APCd0fuCvaYQcg.jpeg" /></figure><p>We already have it, we will create our own Widget that implements <strong>PreferredSizeWidget</strong>.</p><p>What we want</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/488/1*qgVnYbeBYotLRus8QZ9w2A.png" /></figure><p>How we do it so that when pressing the menu button of our <strong>AppBar</strong> the side menu opens.</p><blockquote>We can do it in 2 ways:</blockquote><h4>Using the `AppBar` widget</h4><p>With this the <strong>AppBar </strong>is responsible for opening the lateral menu if it is inside a <strong>Scaffold</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f81c3e9fce28a097f301fa1ab8e4702b/href">https://medium.com/media/f81c3e9fce28a097f301fa1ab8e4702b/href</a></iframe><h4>Using a Custom widget</h4><p>With this we have more flexibility, to do it we can use <strong>GlobalKey</strong> of the type <strong>ScaffoldState</strong> or using the <strong>InheritedWidget</strong> of <strong>Scaffold</strong>, with that we have access to methods of the State with which we can open the <strong>Drawer</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8c314c3ca0f93dc91ddf560eed697260/href">https://medium.com/media/8c314c3ca0f93dc91ddf560eed697260/href</a></iframe><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*V0Y7U_7SCA_HDmSdADHr7Q.gif" /></figure><p>Simple, no? let’s see the second case with the <strong>SliverAppBar</strong>.</p><h3>Case 2</h3><p>We know that the <strong>SliverAppBar</strong> works in the following way:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*LkpLa2HjkPbWt8x6HaZATA.gif" /></figure><p>But what we want is to put a <strong>Card</strong> embedded in our <strong>SliverAppBar</strong> as shown in the following image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/450/1*el1f0s7fHo4fsvfk7YwKeQ.png" /></figure><p>Wait, but the content that is inside the <strong>SliverAppBar</strong> is clipped so it can not exceed the constraints, and now what do we do?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*oL3ZmToEvMl-BIrVFrGhXQ.jpeg" /></figure><p>Quiet, let’s see the source code of the <strong>SliverAppBar</strong>, oh surprise, it’s a <strong>StatefulWidget</strong> that uses a <a href="https://api.flutter.dev/flutter/widgets/SliverPersistentHeader/SliverPersistentHeader.html"><strong>SliverPersistentHeader</strong></a> inside, that’s the secret.</p><p>We are going to create our own <strong>SliverPersistentHeaderDelegate</strong> in order to use the <strong>SliverPersistentHeader</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/234326f93f0d8bdd443ac833b34857a8/href">https://medium.com/media/234326f93f0d8bdd443ac833b34857a8/href</a></iframe><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*zuh9z4eWXYPV5XKPVoUo2A.gif" /></figure><p>Done, we already have our 2 cases resolved.</p><p>You can see the examples in the following repo.</p><p><a href="https://github.com/diegoveloper/flutter-samples/tree/master/lib/appbar_sliverappbar">diegoveloper/flutter-samples</a></p><h3>Conclusion</h3><p>Many times we get desperate when we do not find some Widget properties that Flutter provides, but it is always a good practice to check the source code of how the current Widgets are built to understand how Flutter works and the different options we have to create our own Widgets.</p><p>You can follow me on Twitter</p><p><a href="https://twitter.com/diegoveloper">Diego Velasquez</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c4f67c4e076f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/flutter-increase-the-power-of-your-appbar-sliverappbar-c4f67c4e076f">Flutter: Increase the power of your AppBar &amp; SliverAppBar</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Comunicación entre Widgets]]></title>
            <link>https://medium.com/comunidad-flutter/comunicaci%C3%B3n-entre-widgets-5f61b6c2e56c?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/5f61b6c2e56c</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[mobile-development]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Thu, 21 Mar 2019 15:50:25 GMT</pubDate>
            <atom:updated>2019-03-21T15:50:25.726Z</atom:updated>
            <content:encoded><![CDATA[<p>Este artículo es una traducción al español de la que escribí originalmente y lo puedes encontrar en el siguiente <a href="https://medium.com/@diegoveloper/flutter-communication-between-widgets-f5590230df1e">enlace</a>.</p><p>He visto muchas veces esta pregunta en StackOverflow y en otros foros/redes sociales, cuando empezamos con Flutter, tenemos la duda de cómo podemos comunicarnos entre widgets, es decir de Widget padre a Widget hijo y viceversa.</p><p>Tenemos muchas formas y maneras de poder comunicar Widgets entre ellos.<br>Vamos a repasar cada una de estas, desde la más sencilla, hasta la más óptima.</p><h4>Escenario</h4><p>Como escenario vamos a tener 2 tabs y 2 widgets hijos.</p><p>Los 3 widgets los creamos Stateful ya que vamos a actualizar el contenido, parte del código sería así.</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a1349215bed73bc0a2bf83ed20c710da/href">https://medium.com/media/a1349215bed73bc0a2bf83ed20c710da/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1f88ed2fede84cd61d33b8eed7dd0cb2/href">https://medium.com/media/1f88ed2fede84cd61d33b8eed7dd0cb2/href</a></iframe><p>Child 2</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1e4c716a47f023bdf684a87c7e290e23/href">https://medium.com/media/1e4c716a47f023bdf684a87c7e290e23/href</a></iframe><p>Resultado</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/264/1*sO5ptBXBDlvup2DIyXCWeQ.gif" /></figure><p>Ahora, si ven la UI de nuestro ejemplo, hemos creado varios botones de acción, cada acción representa lo siguiente:</p><p><strong>Acción 1 </strong><em>Actualizar el contenido del widget Child 1 desde el widget Parent.</em></p><p><strong>Acción 2 </strong><em>Actualizar el contenido de widget Parent desde el widget Child 1.</em></p><p><strong>Acción 3 </strong><em>Actualizar el contenido del widget Child 2 desde el widget Child 1.</em></p><p><strong>Acción 4 </strong><em>Cambiar de tab desde el widget Child 1 hacia el widget Child 2.</em></p><blockquote>Vamos a ver paso a paso cada una de estas acciones y qué opciones tenemos para realizarlas.</blockquote><h3>Acción 1</h3><p><em>Actualizar el contenido del widget Child 1 desde el widget Parent.</em></p><p>Resultado</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*e7H5zBTHckarRE1AIP5JVA.gif" /></figure><h4>Opción 1:</h4><p>Actualizar el widget pasando un parámetro (definido dentro del widget Child). Luego necesitamos modificar el Child para mostrar el parámetro si es que existe alguno.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/533521e924475b409e3ad738a97a9f01/href">https://medium.com/media/533521e924475b409e3ad738a97a9f01/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2db75c324411568c977f9d72cbc8a670/href">https://medium.com/media/2db75c324411568c977f9d72cbc8a670/href</a></iframe><p>Nota: Estamos preguntando si el parámetro widget.title no trae un valor nulo, de otra manera se mostrará “Page 1”.</p><h4>Opción 2:</h4><p>Definir un GlobalKey con la clase State de nuestro widget Child 1. Tendremos que cambiar la clase a pública, así que quitamos el guión bajo para que nuestra clase quede así : Child1PageState.</p><p>Establecemos el GlobalKey como key de nuestro widget Child 1.</p><p>Creamos un método en nuestro widget Child 1 el cual refrescará el contenido con un nuevo valor.</p><p>Llamamos al método definido en Child1State desde nuestro widget Parent.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dad3664ad8b7d3c0d1524117efc0156a/href">https://medium.com/media/dad3664ad8b7d3c0d1524117efc0156a/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8db78df0ca93607f7e2ad24b36fc2324/href">https://medium.com/media/8db78df0ca93607f7e2ad24b36fc2324/href</a></iframe><h4>Opción 3:</h4><p>Usando InheritedWidget para guardar los datos desde el widget Parent y restaurar los datos desde el widget Child 1.</p><p>Después de actualizar el widget Parent con el nuevo valor, podemos acceder a los datos del InheritedWidget desde cualquier widget que se encuentre en nuestro árbol de Widgets.</p><p>Código actualizado:</p><p>Parent and InheritedWidget</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1ee0147ab35ed65638c1bdc38fbe811d/href">https://medium.com/media/1ee0147ab35ed65638c1bdc38fbe811d/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/16e2a673ded59898025ad657520c87cd/href">https://medium.com/media/16e2a673ded59898025ad657520c87cd/href</a></iframe><p>Nota: Si te gusta este modo, te recomiendo que revises este gran Package llamado: <a href="https://pub.dartlang.org/packages/scoped_model"><strong>ScopedModel</strong></a></p><h3>Acción 2</h3><p><em>Actualizar el contenido de widget Parent desde el widget Child 1.</em></p><p>Resultado</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*kdh6VqBp5vZk0FKEfynaDA.gif" /></figure><h4>Opción 1:</h4><p>Usando CallBacks, crear un método en el widget Parent, pasar el método como callback desde nuestro widget Parent a nuestro widget Child.</p><p>Crear un parámetro callback en nuestro widget Child.</p><p>Ejecutar el callback desde nuestro widget Child.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1becf7a50e4059679dce3fb7df3af294/href">https://medium.com/media/1becf7a50e4059679dce3fb7df3af294/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe7f563fbcca817eb180e8aea5bd1156/href">https://medium.com/media/fe7f563fbcca817eb180e8aea5bd1156/href</a></iframe><h3>Acción 3</h3><p><em>Actualizar el contenido del widget Child 2 desde el widget Child 1.</em></p><p>Resultado</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*FFrkip7_lAIYnwioVW0x6Q.gif" /></figure><h4>Opción 1:</h4><p>Debido a que el widget Child 2 no está construido aún ( Estamos usando tabs y el widget visible es el Child 1)</p><p>Usar InheritedWidget para guardar el valor es la mejor opción.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d545848e019fc3246962ccec5c5e0185/href">https://medium.com/media/d545848e019fc3246962ccec5c5e0185/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f3f9334eef9343f7d9538381379a1379/href">https://medium.com/media/f3f9334eef9343f7d9538381379a1379/href</a></iframe><p>Child 2</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a16b5a2062690142e28548f8aca42b70/href">https://medium.com/media/a16b5a2062690142e28548f8aca42b70/href</a></iframe><h3>Acción 4</h3><p><em>Cambiar de tab desde el widget Child 1 hacia el widget Child 2.</em></p><p>Resultado</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*kIZJa1_i0OcsqymMxk04zA.gif" /></figure><h4>Opción 1:</h4><p>Pasar el tabController como parámetro desde el widget Parent hacia el widget Child 1.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5072655b8717c0e5eba1bf4c27f1dd26/href">https://medium.com/media/5072655b8717c0e5eba1bf4c27f1dd26/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c12eb17d1837dcd243c53d6c3ddd4812/href">https://medium.com/media/c12eb17d1837dcd243c53d6c3ddd4812/href</a></iframe><h4>Opción 2:</h4><p>Pasar un callBack desde el widget Parent hacia el widget Child 1 y cambiar el índice de nuestro tabController.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a1ae1c5a314c669533e0eda09d4fa78f/href">https://medium.com/media/a1ae1c5a314c669533e0eda09d4fa78f/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/793d0f41021b74be86a3b8aceddda4c1/href">https://medium.com/media/793d0f41021b74be86a3b8aceddda4c1/href</a></iframe><h4>Opción 3:</h4><p>Poner el tabController dentro de nuestro InheritedWidget, llamar a este desde nuestro widget Child 1 y cambiar el índice de nuestro tabController.</p><p>Código actualizado:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/34707f76c203126b8d9409666e9d8f42/href">https://medium.com/media/34707f76c203126b8d9409666e9d8f42/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe3facf01e84d6c58a45e4e2dad3f2d0/href">https://medium.com/media/fe3facf01e84d6c58a45e4e2dad3f2d0/href</a></iframe><h3>Conclusión</h3><p>Es bueno usar las herramientas que Flutter provee para que puedan ver el performance de cada uno, lo ideal es que al momento de pasar valores se reconstruyan los mínimos widgets posibles.<br>Compártenos si tienes otra forma de comunicar Widgets.</p><p>Puedes revisar el código fuente en mi repo de flutter-samples <a href="https://github.com/diegoveloper/flutter-samples"><strong>https://github.com/diegoveloper/flutter-samples</strong></a></p><h3>References</h3><p><a href="https://docs.flutter.io/flutter/widgets/InheritedWidget-class.html">InheritedWidget class - widgets library - Dart API</a></p><p><a href="https://flutter.dev/docs/development/ui/interactive">https://flutter.dev/docs/development/ui/interactive</a></p><p>Sígueme en Twitter:</p><p><a href="https://twitter.com/diegoveloper">Diego Velasquez</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5f61b6c2e56c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/comunidad-flutter/comunicaci%C3%B3n-entre-widgets-5f61b6c2e56c">Comunicación entre Widgets</a> was originally published in <a href="https://medium.com/comunidad-flutter">Comunidad Flutter</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter: Communication between widgets]]></title>
            <link>https://medium.com/flutter-community/flutter-communication-between-widgets-f5590230df1e?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/f5590230df1e</guid>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[widget]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[dart]]></category>
            <category><![CDATA[android-app-development]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Thu, 21 Mar 2019 05:28:56 GMT</pubDate>
            <atom:updated>2019-03-21T16:08:16.374Z</atom:updated>
            <content:encoded><![CDATA[<p>I have seen this question many times in StackOverflow and in other forums / social networks, when we started with Flutter, we have the question of how we can communicate between widgets, that is, from parent Widget to child Widget and vice versa.</p><p>We have many ways of communicating between widgets.<br>We will review each of the ways, from the simplest to the most optimal.</p><h4>Scenario</h4><p>As a scenario we will have 2 tabs and 2 child widgets.</p><p>We created the 3 widgets as Stateful since we are going to update the content, part of the code would be like this.</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a1349215bed73bc0a2bf83ed20c710da/href">https://medium.com/media/a1349215bed73bc0a2bf83ed20c710da/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1f88ed2fede84cd61d33b8eed7dd0cb2/href">https://medium.com/media/1f88ed2fede84cd61d33b8eed7dd0cb2/href</a></iframe><p>Child 2</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1e4c716a47f023bdf684a87c7e290e23/href">https://medium.com/media/1e4c716a47f023bdf684a87c7e290e23/href</a></iframe><p>Result</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/264/1*sO5ptBXBDlvup2DIyXCWeQ.gif" /></figure><p>Now, if you see the UI of our example, we have created several action buttons, each action represents the following:</p><p><strong>Action 1 </strong><em>Update the content of the Child 1 widget from the Parent widget.</em></p><p><strong>Action 2 </strong><em>Update the content of the Parent widget from the Child 1 widget.</em></p><p><strong>Action 3 </strong><em>Update the content of the Child 2 widget from the Child 1 widget.</em></p><p><strong>Action 4 </strong><em>Change the tab from Child 1 widget to Child 2 widget.</em></p><blockquote>We will see step by step each of these actions and what options we have to do it.</blockquote><h3>Action 1</h3><p><em>Update the content of the Child 1 widget from the Parent widget.</em></p><p>Result</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*e7H5zBTHckarRE1AIP5JVA.gif" /></figure><h4>Option 1:</h4><p>Update the widget passing a parameter (defined inside the child). Then we need to modify the child also to display the param if there is any.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/533521e924475b409e3ad738a97a9f01/href">https://medium.com/media/533521e924475b409e3ad738a97a9f01/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2db75c324411568c977f9d72cbc8a670/href">https://medium.com/media/2db75c324411568c977f9d72cbc8a670/href</a></iframe><p>Note: we are asking if there is any non-value param from widget.title, otherwise It will display the value “Page 1”.</p><h4>Option 2:</h4><p>Define a GlobalKey with State class of the Child 1. We will have to make the State class public, so remove the underscore : Child1PageState<br>Set the GlobalKey as a key for the Child1 Widget.<br>Create a method on the Child1 widget which will refresh the Widget with the new value.<br>Call the method defined in Child1State from Parent Widget.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dad3664ad8b7d3c0d1524117efc0156a/href">https://medium.com/media/dad3664ad8b7d3c0d1524117efc0156a/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8db78df0ca93607f7e2ad24b36fc2324/href">https://medium.com/media/8db78df0ca93607f7e2ad24b36fc2324/href</a></iframe><h4>Option 3:</h4><p>Using InheritedWidget to store the data from Parent Widget and restore the data from Child1 Widget.<br>After we refresh the Parent Widget with the new value, we can access to that InheritedWidget from any Widget in the Widget tree.</p><p>Code updated:</p><p>Parent and InheritedWidget</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1ee0147ab35ed65638c1bdc38fbe811d/href">https://medium.com/media/1ee0147ab35ed65638c1bdc38fbe811d/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/16e2a673ded59898025ad657520c87cd/href">https://medium.com/media/16e2a673ded59898025ad657520c87cd/href</a></iframe><p>Note: If you like this approach I recommend you to use this awesome package called: <a href="https://pub.dartlang.org/packages/scoped_model"><strong>ScopedModel</strong></a></p><h3><strong>Action 2</strong></h3><p><em>Update the content of the Parent widget from the Child 1 widget.</em></p><p>Result</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*kdh6VqBp5vZk0FKEfynaDA.gif" /></figure><h4>Option 1:</h4><p>Using CallBacks , create a method in the Parent widget, pass the method as a callback from your Parent Widget to your Child Widget.<br>Create Callback param in your Child Widget.<br>Execute the callback from your Child Widget.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1becf7a50e4059679dce3fb7df3af294/href">https://medium.com/media/1becf7a50e4059679dce3fb7df3af294/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe7f563fbcca817eb180e8aea5bd1156/href">https://medium.com/media/fe7f563fbcca817eb180e8aea5bd1156/href</a></iframe><h3><strong>Action 3</strong></h3><p><em>Update the content of the Child 2 widget from the Child 1 widget.</em></p><p>Result</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*FFrkip7_lAIYnwioVW0x6Q.gif" /></figure><h4>Option 1:</h4><p>Because the Child 2 Widget is not built yet (we are using tabs and Child 1 widget is the current) Using InheritedWidget to store the value is the best option.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d545848e019fc3246962ccec5c5e0185/href">https://medium.com/media/d545848e019fc3246962ccec5c5e0185/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f3f9334eef9343f7d9538381379a1379/href">https://medium.com/media/f3f9334eef9343f7d9538381379a1379/href</a></iframe><p>Child 2</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a16b5a2062690142e28548f8aca42b70/href">https://medium.com/media/a16b5a2062690142e28548f8aca42b70/href</a></iframe><h3><strong>Action 4</strong></h3><p><em>Change the tab from Child 1 widget to Child 2 widget.</em></p><p>Result</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/288/1*kIZJa1_i0OcsqymMxk04zA.gif" /></figure><h4>Option 1:</h4><p>Pass the tabController as a parameter from Parent Widget to Child 1 Widget.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5072655b8717c0e5eba1bf4c27f1dd26/href">https://medium.com/media/5072655b8717c0e5eba1bf4c27f1dd26/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c12eb17d1837dcd243c53d6c3ddd4812/href">https://medium.com/media/c12eb17d1837dcd243c53d6c3ddd4812/href</a></iframe><h4>Option 2:</h4><p>Pass a callBack from Parent to Child 1 Widget and change the index of the controller.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a1ae1c5a314c669533e0eda09d4fa78f/href">https://medium.com/media/a1ae1c5a314c669533e0eda09d4fa78f/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/793d0f41021b74be86a3b8aceddda4c1/href">https://medium.com/media/793d0f41021b74be86a3b8aceddda4c1/href</a></iframe><h4>Option 3:</h4><p>Set the tabController inside InheritedWidget , call it from Child 1 Widget and change the index of the controller.</p><p>Code updated:</p><p>Parent</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/34707f76c203126b8d9409666e9d8f42/href">https://medium.com/media/34707f76c203126b8d9409666e9d8f42/href</a></iframe><p>Child 1</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe3facf01e84d6c58a45e4e2dad3f2d0/href">https://medium.com/media/fe3facf01e84d6c58a45e4e2dad3f2d0/href</a></iframe><h3>Conclusion</h3><p>It is good to use the tools that Flutter provides so you can check the performance of each one, the ideal is that when passing values, the minimum possible widgets are rebuilt.<br>Let us know if you have another ways to communicate Widgets.</p><p>You can check the source code in my flutter-samples repo <a href="https://github.com/diegoveloper/flutter-samples"><strong>https://github.com/diegoveloper/flutter-samples</strong></a></p><h3>References</h3><p><a href="https://docs.flutter.io/flutter/widgets/InheritedWidget-class.html">InheritedWidget class - widgets library - Dart API</a></p><p><a href="https://flutter.dev/docs/development/ui/interactive">https://flutter.dev/docs/development/ui/interactive</a></p><p>You can follow me on Twitter</p><p><a href="https://twitter.com/diegoveloper">Diego Velasquez</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f5590230df1e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/flutter-communication-between-widgets-f5590230df1e">Flutter: Communication between widgets</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter: App Clone — Android Messages]]></title>
            <link>https://medium.com/@diegoveloper/flutter-app-clone-android-messages-e4b034a6c893?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/e4b034a6c893</guid>
            <category><![CDATA[dart]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[mobile-development]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Thu, 29 Nov 2018 19:29:45 GMT</pubDate>
            <atom:updated>2018-11-29T19:29:45.723Z</atom:updated>
            <content:encoded><![CDATA[<h3>Flutter: App Clone — Android Messages</h3><p>I have created this new section named <strong>App Clone</strong>, in which I will try to clone the screens of some known apps, as the first example I will show you how to imitate the main screen of the application <strong>Messages</strong> of Android.</p><blockquote>Don’t you know the app? This is how it looks like</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/246/1*uPCDyEbx4xe7oLOHEJHhOQ.gif" /><figcaption>Android Messages App</figcaption></figure><p>The curious thing about this screen is that it brings an interesting animation, when the user scrolls up or down the Fab button changes according to the direction.</p><h3>How to do it in Flutter?</h3><p>Well, very simple, for that we will use the <strong>NotificationListener</strong> widget, for those who didn’t read my previous post, you can take a look here:</p><p><a href="https://medium.com/@diegoveloper/flutter-lets-know-the-scrollcontroller-and-scrollnotification-652b2685a4ac"><strong>Flutter : let’s know the ScrollController and ScrollNotification</strong></a></p><h3>Let started</h3><p>Analyzing the main image we see that it is composed of:</p><p><strong>Scaffold</strong><br><strong>__AppBar</strong><br>____title ‘Messages’<br>____actions<br>______IconButton -&gt; search<br>______IconButton -&gt; dots</p><p><strong>__Body</strong><br>____ListView<br>______Custom StatelessWidget</p><p><strong>__FloatingActionButton</strong> (changes according to the direction)</p><p>That was a quick look at the main outline of the app’s UI. I won’t go into much detail on how to build the Custom StatelessWidget since it is not complicated.</p><p>Translated into code would be the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2b70564dd61fbea54d2e06a7d17fae71/href">https://medium.com/media/2b70564dd61fbea54d2e06a7d17fae71/href</a></iframe><h4><strong>Result</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/263/1*E66HvIgiqZrW9yQfyJMgCQ.png" /><figcaption>Flutter Messages App</figcaption></figure><p>Now, the challenge is how to transform my <strong>FloatingActionButton</strong> when the user scroll and change the direction? For that, our <strong>ListView</strong> must have as parent the <strong>NotificationListener</strong> of the <strong>ScrollNotification</strong> subtype.</p><pre>NotificationListener&lt;ScrollNotification&gt;(<br>              onNotification: (onScrollNotification) {<br>              <br>              },<br>              child: _buildList())</pre><p>With this we are already listening to scroll notifications, now let’s do the logic to know if it is going up or down.</p><p>We have to create a variable to save the current direction:</p><pre>class _AndroidMessagesPageState extends State&lt;AndroidMessagesPage&gt; {</pre><pre>bool isGoingDown = true;</pre><p>Now, the logic inside our <strong>onScrollNotification </strong>callBack</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/92f038df1e5bf262ae88f129ce8044e3/href">https://medium.com/media/92f038df1e5bf262ae88f129ce8044e3/href</a></iframe><p>Refreshing the Fab button according to the direction:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e23ecb21bf7583187eb8bbce57d29b5a/href">https://medium.com/media/e23ecb21bf7583187eb8bbce57d29b5a/href</a></iframe><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/284/1*ILvRTdUZ28YpTrHup5KgWg.gif" /></figure><p>As you can see, we refreshed the Fab button , but the transition isn’t smooth, right?<br>We can improve it by creating our own button and using <strong>AnimatedContainer</strong> for the animation, in the following way.</p><p><a href="https://gist.github.com/diegoveloper/3c18ad5398f2e33c134bcefd187d1f43">https://gist.github.com/diegoveloper/3c18ad5398f2e33c134bcefd187d1f43</a></p><p>And call our new Fab button like this way:</p><pre>floatingActionButton: MyFabButton(isGoingDown)</pre><h3>Final result</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/297/1*Rb2ATV7nL0lO5K2VcF1NVw.gif" /></figure><h3>References</h3><p>You can check the source code in my <strong>flutter-samples</strong> repo <a href="https://github.com/diegoveloper/flutter-samples">https://github.com/diegoveloper/flutter-samples</a></p><p>You can find me on <strong>Twitter</strong>: <a href="http://twitter.com/diegoveloper">@diegoveloper</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e4b034a6c893" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter : let’s know the ScrollController and ScrollNotification]]></title>
            <link>https://medium.com/@diegoveloper/flutter-lets-know-the-scrollcontroller-and-scrollnotification-652b2685a4ac?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/652b2685a4ac</guid>
            <category><![CDATA[scroll]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Tue, 23 Oct 2018 15:44:48 GMT</pubDate>
            <atom:updated>2018-10-23T15:44:48.180Z</atom:updated>
            <content:encoded><![CDATA[<h3>Flutter : let’s know the ScrollController and ScrollNotification</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*RcxwmwhA4Q-3yFnI7iWPCg.png" /></figure><p>In the majority of the apps we do, we have at least one Scrollable Widget.</p><p>In some cases we want to extend the use of our elements within a scroll, for example:</p><p><strong>1-</strong> When we want to know if we reach at the beginning or end of a list. (Either vertical or horizontal).<br><strong>2-</strong> When we want to move between elements of a list programmatically.<br><strong>3-</strong> When we want to know if the scroll of our List started, is in progress or it ended.</p><p>We are going to review these 3 cases in detail.</p><h3>If the list reached the minimum or maximum scroll</h3><p>We start by building a simple app, which has a Text widget at the top that indicates when the minimum or maximum scroll was reached.<br>In the lower part we will have a list of elements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*m9DhXoa7sgFFnSAz7_ig7A.png" /></figure><p>Code:</p><pre>String message = &quot;&quot;;</pre><pre><a href="http://twitter.com/override">@override</a><br>  Widget build(BuildContext context) {<br>    return Scaffold(<br>      appBar: AppBar(<br>        title: Text(&quot;Scroll Limit reached&quot;),<br>      ),<br>      body: Column(<br>        children: &lt;Widget&gt;[<br>          Container(<br>            height: 50.0,<br>            color: Colors.green,<br>            child: Center(<br>              child: Text(message),<br>            ),<br>          ),<br>          Expanded(<br>            child: ListView.builder(<br>              itemCount: 30,<br>              itemBuilder: (context, index) {<br>                return ListTile(title: Text(&quot;Index : $index&quot;));<br>              },<br>            ),<br>          ),<br>        ],<br>      ),<br>    );<br>  }</pre><p>Once we have our widget, the first step is to declare a <strong>ScrollController </strong>variable.</p><pre>ScrollController _controller;</pre><p>We instantiate it within our <strong>initState</strong> method, in the following way:</p><pre><a href="http://twitter.com/override">@override</a><br>  void initState() {<br>    _controller = ScrollController();<br>    super.initState();<br>  }</pre><p>Then we assign this <strong>_controller</strong> to our ListView.</p><pre>ListView.builder(<br>              controller: <strong>_controller</strong>,<br>              itemCount: 30,<br>              itemBuilder: (context, index) {<br>                return ListTile(title: Text(&quot;Index : $index&quot;));<br>              },<br>            )</pre><p>With this we have our <strong>ListView</strong> connected with our <strong>ScrollController</strong>, we just have to listen to the events to determine what we want.</p><h4>Listening to events</h4><pre>_scrollListener() {<br> <br> }</pre><pre><a href="http://twitter.com/override">@override</a><br>  void initState() {<br>    _controller = ScrollController();<br>    _controller.addListener(_scrollListener);<br>    super.initState();<br>  }</pre><p>Now we are listening to the Scroll events, but how we can know if the scroll reach the top or bottom.</p><p>We just have to add these validations:</p><pre>_scrollListener() {<br>    if (_controller.offset &gt;= _controller.position.maxScrollExtent &amp;&amp;<br>        !_controller.position.outOfRange) {<br>      setState(() {<br>        message = &quot;reach the bottom&quot;;<br>      });<br>    }<br>    if (_controller.offset &lt;= _controller.position.minScrollExtent &amp;&amp;<br>        !_controller.position.outOfRange) {<br>      setState(() {<br>        message = &quot;reach the top&quot;;<br>      });<br>    }<br>  }</pre><p>We test by scrolling up or down and get this result</p><p><strong>Result</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/308/1*FscaBcSBG7fWDifX54YbcA.gif" /></figure><p>That’s it, now we know when our list reached the top or bottom of the scroll, let’s see the other case.</p><h3>Move between elements of a list.</h3><p>We make a screen similar to the previous one, we add 2 separate buttons which we will use to move up or down between the elements of the list.<br>We also create a variable in which we define the size of our elements in the list, this variable <strong>itemSize</strong> we will use also to move that number of pixels up or down.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*dS7suRrLoj-tfV781zGpqQ.png" /></figure><p>Code:</p><pre>final <strong>itemSize</strong> = 100.0;</pre><pre>_moveUp() {<br>     //Add logic here<br>  }</pre><pre>_moveDown() {<br>   //Add logic here<br>  }</pre><pre><a href="http://twitter.com/override">@override</a><br>  Widget build(BuildContext context) {<br>    return Scaffold(<br>      appBar: AppBar(<br>        title: Text(&quot;Scroll Movement&quot;),<br>      ),<br>      body: Column(<br>        children: &lt;Widget&gt;[<br>          Container(<br>            height: 50.0,<br>            color: Colors.green,<br>            child: Center(<br>              child: Row(<br>                mainAxisAlignment: MainAxisAlignment.spaceBetween,<br>                children: &lt;Widget&gt;[<br>                  RaisedButton(<br>                    child: Text(&quot;up&quot;),<br>                    onPressed: _moveUp,<br>                  ),<br>                  RaisedButton(<br>                    child: Text(&quot;down&quot;),<br>                    onPressed: _moveDown,<br>                  )<br>                ],<br>              ),<br>            ),<br>          ),<br>          Expanded(<br>            child: ListView.builder(<br>              itemCount: 30,<br>              itemExtent: <strong>itemSize</strong>,<br>              itemBuilder: (context, index) {<br>                return ListTile(title: Text(&quot;Index : $index&quot;));<br>              },<br>            ),<br>          ),<br>        ],<br>      ),<br>    );<br>  }</pre><p>Now we have to create our <strong>ScrollController</strong> and link it with our <strong>ListView</strong></p><pre>ScrollController <strong>_controller</strong>;</pre><pre><a href="http://twitter.com/override">@override</a><br>  void initState() {<br>    <strong>_controller</strong> = ScrollController();<br>    super.initState();<br>  }</pre><pre>...</pre><pre>child: ListView.builder(<br>              controller: <strong>_controller</strong>,<br>              itemCount: 30,<br>              itemExtent: itemSize,<br>              itemBuilder: (context, index) {<br>                return ListTile(title: Text(&quot;Index : $index&quot;));<br>              },<br>            ),</pre><p>Once we have connected the <strong>ScrollController</strong> to our list, moving is very simple.</p><p>We can do it in 2 ways.</p><h4>With animation:</h4><p>When we want the scroll to have animation, it receives the offset in pixels as parameters , the <a href="https://docs.flutter.io/flutter/animation/Curves-class.html"><strong>Curve type</strong></a> animation , and the duration.</p><pre>_controller.animateTo(pixelsToMove,<br> curve: Curves.linear, duration: Duration (milliseconds: 500));</pre><h4>Without animation:</h4><p>When we want the scrolling without animation, it only receives the offset in pixels as parameter.</p><pre>_controller.jumpTo(pixelsToMove);</pre><p>For our example we are going to use the animated way since the user has to perceive the scrolling.</p><pre>_moveUp() {<br>    _controller.animateTo(_controller.offset - itemSize,<br>        curve: Curves.linear, duration: Duration(milliseconds: 500));<br>  }</pre><pre>_moveDown() {<br>    _controller.animateTo(_controller.offset + itemSize,<br>        curve: Curves.linear, duration: Duration(milliseconds: 500));<br>  }</pre><p>We use the current offset of our <strong>ScrollController </strong>which has the current pixels of its position, and we add or remove the <strong>itemSize</strong> which has the height of our current item from the list.</p><p><strong>Result</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/336/1*bo5OibG4qCRm6HcLmVEpKg.gif" /></figure><blockquote>Very simple, no? Yes, that’s right, that’s Flutter.</blockquote><p>Finally we are going to review the last case.</p><h3>Listen ScrollNotifications.</h3><p>For this we create a UI similar to that of case one, in which we will display the state of our <strong>Scroll</strong> at the top.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*bXxeU8_ZMrU2mGquxJg1Dg.png" /></figure><p>Code:</p><pre>String message = &quot;&quot;;</pre><pre><a href="http://twitter.com/override">@override</a><br>  Widget build(BuildContext context) {<br>    return Scaffold(<br>      appBar: AppBar(<br>        title: Text(&quot;Scroll Status&quot;),<br>      ),<br>      body: Column(<br>        children: &lt;Widget&gt;[<br>          Container(<br>            height: 50.0,<br>            color: Colors.green,<br>            child: Center(<br>              child: Text(message),<br>            ),<br>          ),<br>          Expanded(<br>            child: ListView.builder(<br>                itemCount: 30,<br>                itemBuilder: (context, index) {<br>                  return ListTile(title: Text(&quot;Index : $index&quot;));<br>                },<br>              ),<br>          ),<br>        ],<br>      ),<br>    );<br>  }</pre><p>Once we have that ready, we will need to use our <strong>NotificationListener</strong> Widget to capture notifications from our List.</p><p>So, first we add <strong>NotificationListener</strong> as a new container of our <strong>ListView</strong> and we will listen the events of type <strong>ScrollNotification</strong>,</p><pre>Expanded(<br>            child: NotificationListener&lt;ScrollNotification&gt;(<br>              <br>              child: ListView.builder(<br>                itemCount: 30,<br>                itemBuilder: (context, index) {<br>                  return ListTile(title: Text(&quot;Index : $index&quot;));<br>                },<br>              ),<br>            ),<br>          ),</pre><p>Now we’ll have implement the <strong>onNotification</strong> callback.<br>The code would look like this:</p><pre>Expanded(<br>            child: NotificationListener&lt;ScrollNotification&gt;(<br>              onNotification: (scrollNotification) {<br>                //do your logic<br>              },<br>              child: ListView.builder(<br>                itemCount: 30,<br>                itemBuilder: (context, index) {<br>                  return ListTile(title: Text(&quot;Index : $index&quot;));<br>                },<br>              ),<br>            ),<br>          ),</pre><p>In order to identify the type of <strong>ScrollNotification</strong>, we do it in the following way:</p><pre>Expanded(<br>            child: NotificationListener&lt;ScrollNotification&gt;(<br>              onNotification: (scrollNotification) {<br>                if (scrollNotification is ScrollStartNotification) {<br>                  _onStartScroll(scrollNotification.metrics);<br>                } else if (scrollNotification is ScrollUpdateNotification) {<br>                  _onUpdateScroll(scrollNotification.metrics);<br>                } else if (scrollNotification is ScrollEndNotification) {<br>                  _onEndScroll(scrollNotification.metrics);<br>                }<br>              },<br>              child: ListView.builder(<br>                itemCount: 30,<br>                itemBuilder: (context, index) {<br>                  return ListTile(title: Text(&quot;Index : $index&quot;));<br>                },<br>              ),<br>            ),<br>          ),</pre><p>We created a method to update our top label.</p><pre>_onStartScroll(ScrollMetrics metrics) {<br>      setState(() {<br>        message = &quot;Scroll Start&quot;;<br>      });<br>    }</pre><pre>_onUpdateScroll(ScrollMetrics metrics) {<br>      setState(() {<br>        message = &quot;Scroll Update&quot;;<br>      });<br>    }</pre><pre>_onEndScroll(ScrollMetrics metrics) {<br>      setState(() {<br>        message = &quot;Scroll End&quot;;<br>      });<br>    }</pre><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/350/1*_QUSvcpBYYX8v_SiXWpeRA.gif" /></figure><p>Super easy again, right?</p><h3>Conclusion</h3><p>As we have seen, using the <strong>ScrollController</strong> and <strong>ScrollNotification</strong> is not complicated. Also you can go deeper and play with ScrollPhysics and ScrollPosition .We can create very nice things if we want, like this: <a href="https://twitter.com/diegoveloper/status/1054400640795992064">https://twitter.com/diegoveloper/status/1054400640795992064</a><br>You just have to let your imagination fly :)<br>And remember, with Flutter never say no to your designer.</p><p>You can check the source code in my flutter-samples repo <a href="https://github.com/diegoveloper/flutter-samples"><strong>https://github.com/diegoveloper/flutter-samples</strong></a></p><h3>References</h3><p><a href="https://docs.flutter.io/flutter/widgets/ScrollController-class.html">https://docs.flutter.io/flutter/widgets/ScrollController-class.html</a><br><a href="https://docs.flutter.io/flutter/animation/Curves-class.html">https://docs.flutter.io/flutter/animation/Curves-class.html</a><br><a href="https://docs.flutter.io/flutter/widgets/ScrollNotification-class.html">https://docs.flutter.io/flutter/widgets/ScrollNotification-class.html</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=652b2685a4ac" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter : Widget Size and Position]]></title>
            <link>https://medium.com/@diegoveloper/flutter-widget-size-and-position-b0a9ffed9407?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/b0a9ffed9407</guid>
            <category><![CDATA[widget]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[positioning]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Mon, 24 Sep 2018 02:38:21 GMT</pubDate>
            <atom:updated>2018-10-22T16:18:15.532Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*ntgLYlJtPXro-4RlbXc9RA.png" /></figure><p>I have read many questions about how we can obtain the dimensions or positions of the widgets that we have on screen.</p><p>In some cases we find ourselves in situations in which we want to achieve that for any reason.</p><p>The widget doesn’t have position or size by itself, in order to achieve this it’s necessary that we obtain the <strong>RenderBox</strong> associated with the context of our <strong>Widget</strong>.</p><blockquote>But how do we do this?</blockquote><p>Let’s start building a demo app which has 3 panels of different colors, Red, Purple and Green inside a Column and we have two buttons at the bottom to get the Size and Position.</p><p>This is the code of the demo app:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8ae8dd57bb21023e0de0b81e08869d66/href">https://medium.com/media/8ae8dd57bb21023e0de0b81e08869d66/href</a></iframe><p>And the result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*ntgLYlJtPXro-4RlbXc9RA.png" /></figure><p>Ok so now the question is : How can I get the size and position of each panel?</p><p>Let’s focus on just one panel for this post (Red panel) , after we know how to get the size and position for one panel it should be easy for the others.</p><h3>Get the size of a Widget</h3><p>In order to do that, we need our <strong>Widget</strong> to have a <strong>Key</strong>, for this we create a <strong>GlobalKey</strong> and assign it to our <strong>Widget</strong>.</p><pre>//creating Key for red panel<br>GlobalKey _keyRed = GlobalKey();<br>...<br>//set key<br>    Flexible(<br>             flex: 2,<br>             child: Container(<br>               key: _keyRed,<br>               color: Colors.red,<br>             ),<br>     ),</pre><p>Once our Widget already has a Key, we can use this Key to be able to obtain the size in the following way:</p><pre>_getSizes() {<br>    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();<br>    final sizeRed = renderBoxRed.size;<br>    print(&quot;SIZE of Red: $sizeRed&quot;);<br> }</pre><p>If we press the Get Sizes button, you’ll get this result in the console:</p><pre>flutter: SIZE of Red: Size(375.0, 152.9)</pre><p>now we know that our Red panel has 375.0 as width and 152.9 as height</p><p>It was easy, right?</p><p>Let’s go to obtain the position in which our <strong>Widget</strong> is located.</p><h3>Get the position of a Widget</h3><p>In the same way that we did previously, our Widget must have an associated Key.</p><p>Now we update the method to obtain the position of the Widget relative to the top-left of the defined position (in this case we are using 0.0 it means the top-left corner of our current screen).</p><pre>_getPositions() {<br>    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();<br>    final positionRed = renderBoxRed.localToGlobal(Offset.zero);<br>    print(&quot;POSITION of Red: $positionRed &quot;);<br>  }</pre><p>If we press the Get Positions button, you’ll get this result in the console:</p><pre>flutter: POSITION of Red: Offset(0.0, 76.0)</pre><p>It means our Widget start from 0.0 from the X axis and 76.0 from the Y axis from TOP-LEFT.</p><p>Why 76.0? That’s because there is an AppBar above that has a height of 76.0.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/441/1*MU0zKEWN3IVRVNIFw5mNAA.jpeg" /></figure><p>So we already know how to get the size and position of our Widgets, well so far. Yay!!</p><p>But what happens if I’m interested in getting the size or position at the beginning, without having to press a button for it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/258/1*ld2J7qNKDW1lNg9tI4SUsQ.png" /></figure><p>Ok then let’s call our methods in our constructor.</p><pre>_MainSizeAndPositionState(){<br>     _getSizes();<br>     _getPositions();<br>   }</pre><p>Run the app and …. oh we have an error here:</p><pre>flutter: The following NoSuchMethodError was thrown building Builder:<br>flutter: The method &#39;findRenderObject&#39; was called on null.<br>flutter: Receiver: null<br>flutter: Tried calling: findRenderObject()</pre><p>Ok let’s try calling the methods from the <strong>initState , </strong>it should work ….. or no</p><pre><a href="http://twitter.com/override">@override</a><br>  void initState() {<br>    _getSizes();<br>    _getPositions();<br>    super.initState();<br>  }</pre><p>Run the app and … a little different but the same error:</p><pre>flutter: Another exception was thrown: NoSuchMethodError: The method &#39;findRenderObject&#39; was called on null.</pre><p>So, we have a problem, we can not get the size or position at the beginning, so <strong>how do I do it?</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*MgQLuaNskr7Ls49d.png" /></figure><p>This happens because the context is not yet associated with our state.</p><blockquote>You can find more information about the lifecycle of the Widgets here: <a href="https://medium.com/flutter-community/widget-state-buildcontext-inheritedwidget-898d671b7956">https://medium.com/flutter-community/widget-state-buildcontext-inheritedwidget-898d671b7956</a></blockquote><p>So we have to wait for our <strong>Widget</strong> to finish rendering, but how can achieve that?</p><p>There is a simple way, as I show you below.</p><pre><a href="http://twitter.com/override">@override</a><br>  void initState() {<br>    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);<br>    super.initState();<br>  }</pre><pre> _afterLayout(_) {<br>    _getSizes();<br>    _getPositions();<br>  }</pre><p>With this you make sure to call your methods after the layout is completed.</p><p>If we run our app again, this is the result:</p><pre>flutter: SIZE of Red: Size(375.0, 152.9)<br>flutter: POSITION of Red: Offset(0.0, 76.0)</pre><p>Finally!!!</p><p>You can also review this package created by my friend <a href="https://medium.com/u/91cb19edfc82">Simon Lightfoot</a> here: <a href="https://pub.dartlang.org/packages/after_layout">https://pub.dartlang.org/packages/after_layout</a></p><h3>Conclusion</h3><p>Many times, we get complicated by things that are very simple, it is necessary to read the documentation that Flutter provides, anyway every day we learn new things.</p><p>You can check the source code in my flutter-samples repo <a href="https://github.com/diegoveloper/flutter-samples"><strong>https://github.com/diegoveloper/flutter-samples</strong></a></p><h3>References</h3><p><a href="https://docs.flutter.io/flutter/rendering/RenderBox-class.html">https://docs.flutter.io/flutter/rendering/RenderBox-class.html</a><br><a href="https://medium.com/flutter-community/widget-state-buildcontext-inheritedwidget-898d671b7956">https://medium.com/flutter-community/widget-state-buildcontext-inheritedwidget-898d671b7956</a><br><a href="https://pub.dartlang.org/packages/after_layout">https://pub.dartlang.org/packages/after_layout</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0a9ffed9407" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter : Firebase Dynamic Link]]></title>
            <link>https://medium.com/@diegoveloper/flutter-firebase-dynamic-link-6f1b79278ce0?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f1b79278ce0</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[deep-linking]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Tue, 07 Aug 2018 20:17:20 GMT</pubDate>
            <atom:updated>2019-08-11T02:47:44.717Z</atom:updated>
            <content:encoded><![CDATA[<p>I’m going to tell you about my experience using <strong>Firebase Dynamic Link</strong> into a Flutter project.</p><p>For those who don’t know about <strong>Firebase Dynamic Link</strong>, here is a video.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FLvY1JMcrPF8%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DLvY1JMcrPF8&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FLvY1JMcrPF8%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac54579ee62d7ef9cf8656254d018d9a/href">https://medium.com/media/ac54579ee62d7ef9cf8656254d018d9a/href</a></iframe><p>As you can see, it’s a tool that has many advantages, in our case, we were very interested in receiving dynamic links.</p><h3>Our requirement</h3><blockquote>After a user is invited to our application, an e-mail is sent with a link, which when selected should follow this flow</blockquote><h3>Scenario 1</h3><h4><strong>The guest user doesn’t have the app installed.</strong></h4><p>The link should redirect to the app store that corresponds App Store/Play Store.</p><h3>Scenario 2</h3><h4>The user does not open the link from the mobile.</h4><p>The link should redirect to a page with links to download the application.</p><h3>Scenario 3</h3><h4>The invited user has the app installed.</h4><p>The link should redirect to the app and after that redirect to the invitation screen.</p><h3>How do we solve it?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*-v29Q7LUl9WovzHcSqgAXQ.jpeg" /></figure><p><strong>Firebase Dynamic Link</strong> was the perfect solution for this requirement.</p><p>In this post I will not go into detail on how to configure <strong>Firebase Dynamic Link</strong> on Android/iOS, there are many tutorials about that.<br>I will detail the integration in <strong>Flutter</strong> for receiving links that contain deep link with different parameters, since when I implemented it I found a bug that I am going to show them.</p><h3>Step 1</h3><p>Create our dynamic Link manually</p><p>You can do so by following this documentation: <a href="https://firebase.google.com/docs/dynamic-links/create-manually">https://firebase.google.com/docs/dynamic-links/create-manually</a></p><h3>Step 2</h3><p>Add the <strong>Firebase Dynamic Link</strong> package in your Flutter project</p><p><a href="https://pub.dartlang.org/packages/firebase_dynamic_links">https://pub.dartlang.org/packages/firebase_dynamic_links</a></p><p>You can read the part where it says <strong><em>Handle Received Dynamic Links</em></strong>, since it details the instructions in case you don’t have it configured.</p><p>Add new package into the <strong>pubspec.yaml</strong> file</p><pre>firebase_dynamic_links: ^0.0.6</pre><h3>Step 3</h3><p>The example that is shown on the plugin page, doesn’t give much detail about where we should put that code block, in my case I had to read the source code of the Plugin to understand what It was doing.</p><p>This is the example code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/078897df126e6cb286f3fdd15c1d0830/href">https://medium.com/media/078897df126e6cb286f3fdd15c1d0830/href</a></iframe><p>Assuming that <strong>MyHomeWidget</strong> is our initial widget that is displayed when the application starts, when creating the Widget and starting the state, they call the <strong>_retrieveDynamicLink</strong> method, which uses the plugin with the following line:</p><pre>final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.retrieveDynamicLink ();<br> final Uri deepLink = data? .link;</pre><p><strong>FirebaseDynamicLinks.instance.retrieveDynamicLink()</strong> is the call that is responsible for obtaining the deep link in the case our application was opened from the dynamic link.</p><h3>Problem 1</h3><p>If our widget was already started, if you open the dynamic link again, it will never go through the initState() method again, so we will never get the deep link.</p><h3>Solution</h3><p>Use the <a href="https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html"><strong>WidgetsBindingObserver</strong></a><strong> </strong>to listen the status of the widget when it resume or pauses.</p><p>So we can do something like this</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9fa7077547c0da602d2193244eab0b2e/href">https://medium.com/media/9fa7077547c0da602d2193244eab0b2e/href</a></iframe><p>Here we make sure that each time our Widget is displayed, the method is invoked to obtain the dynamic Link.</p><h3>Problem 2</h3><p>In iOS, the <strong>AppLifecycleState.resume</strong> is called before the plugin gets the Deep Link.</p><h3>Solution</h3><p>Add a small delay before invoking the <strong>_retrieveDynamicLink</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/92d9f1369fce825de40479c811c8d129/href">https://medium.com/media/92d9f1369fce825de40479c811c8d129/href</a></iframe><p>So far so good, just that I noticed a bug that only happens on iOS.</p><h3>Problem 3</h3><p>In iOS, once we open the app, and get the deep Link using <strong>FirebaseDynamicLinks.instance.retrieveDynamicLink()</strong>, when we call it again, we continue obtaining the last deep Link, that is, since the call will be executed every time the widget enters the state of <strong>AppLifecycleState.resumed</strong>, and it happens, when the application is opened, either from a dynamic link or manually by the user, in iOS I had no way of knowing from where it was opened, because after getting a deep link, the method would bring back the same value even if it came out and entered the app manually.</p><p>When I was reviewing the plugin code for iOS, I saw that when calling the <strong>retrieveDynamicLink</strong> method, what it does is store the value of the deep link in a variable and return it, the problem is that after consuming that method, the variable is never cleaned , as if it does in the case of Android, and therefore that unexpected result in iOS.</p><p>I already sent a Pull Request to solve that issue, but until they accept it, you can change the <strong>pubspec.yaml</strong> file as follows</p><pre>firebase_dynamic_links:<br>  git:<br>    url: <a href="https://github.com/diegoveloper/plugins.git">https://github.com/diegoveloper/plugins.git</a><br>    ref: ff17b724df0bcdf35bb5689b347d7fbef7107615<br>    path: packages/firebase_dynamic_links</pre><h3>UPDATE 08/23/2018</h3><p>Finally the PR was approved (fixed problem 3), now we add the plugin in this way:</p><pre>firebase_dynamic_links: ^0.1.0</pre><h3>UPDATE 07/23/2019 (Breaking change)</h3><p>There is a new version(<a href="https://pub.dev/packages/firebase_dynamic_links/versions/0.5.0">0.5.0</a>) of the firebase_dynamic_links package, now we have two methods to receive the dynamic link.</p><ul><li>getInitialLink a future to retrieve the link that opened the app</li><li>onLink a callback to listen to links opened while the app is active or in background</li></ul><p>You can forget what I wrote before this update, and now it should be easy to use, like this:</p><pre><strong>@override</strong><br>  <strong>void</strong> initState() {<br>    <strong>super</strong>.initState();<br>    <strong>this</strong>.initDynamicLinks();<br>  }<br><br>  <strong>void</strong> initDynamicLinks() <strong>async</strong> {<br>    <strong>final</strong> PendingDynamicLinkData data = <strong>await</strong> FirebaseDynamicLinks.instance.getInitialLink();<br>    <strong>final</strong> Uri deepLink = data?.link;<br><br>    <strong>if</strong> (deepLink != <strong>null</strong>) {<br>      Navigator.pushNamed(context, deepLink.path);<br>    }<br><br>    FirebaseDynamicLinks.instance.onLink(<br>      onSuccess: (PendingDynamicLinkData dynamicLink) <strong>async</strong> {<br>        <strong>final</strong> Uri deepLink = dynamicLink?.link;<br><br>        <strong>if</strong> (deepLink != <strong>null</strong>) {<br>          Navigator.pushNamed(context, deepLink.path);<br>        }<br>      },<br>      onError: (OnLinkErrorException e) <strong>async</strong> {<br>        print(&#39;onLinkError&#39;);<br>        print(e.message);<br>      }<br>    );<br>  }</pre><h3>Conclusion</h3><p>Many times we don’t find much documentation for certain plugins/libraries, and it is always good that we can share our experiences so that we can all learn.<br>If you have another solution for handling deep links don’t hesitate to share it.</p><h3>References</h3><p><a href="https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html">https://docs.flutter.io/flutter/widgets/WidgetsBindingObserver-class.html</a><br><a href="https://pub.dartlang.org/packages/firebase_dynamic_links">https://pub.dartlang.org/packages/firebase_dynamic_links</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f1b79278ce0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter : Shared Element Transitions — Hero — Heroes]]></title>
            <link>https://medium.com/@diegoveloper/flutter-shared-element-transitions-hero-heroes-f1a083cb123a?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/f1a083cb123a</guid>
            <category><![CDATA[shared-element-transition]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[heroes]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Mon, 30 Jul 2018 20:20:46 GMT</pubDate>
            <atom:updated>2018-07-30T20:25:50.412Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/328/1*24T8dSUDCWZcZ46ZKBcy4w.png" /></figure><p>As Android developers, most of us have seen the <em>Shared Element Transition</em>, if we have not seen it, I will explain what it is.</p><blockquote>Shared Element transition are the animations that are shown for certain elements that go from one screen to another, the clearest example is when we have a list of elements with thumbnail images, then we go into the detail of that element, and we see how it is shown an animation from the initial screen, towards the destination screen, moving the image while the transition continues</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*qw_utaFpupWafB4z7DMJWg.gif" /><figcaption>Shared Element Transition example</figcaption></figure><p>In Android perform such animations can be a bit annoying depending on the views we try to communicate, since they can be from an <em>Activity -&gt; Activity</em>, <em>Fragment -&gt; Activity</em>, <em>Activity -&gt; Fragment </em>or <em>Fragment -&gt; Fragment</em>.</p><p>In Flutter this animation has the name of ‘<strong>Hero</strong>’, and now I’m going to show you how easy is it to do it.</p><p>To achieve a simple transition animation, we need two <strong>Heroes</strong>, <strong>Hero</strong> origin and <strong>Hero</strong> destination, the 2 must share the same <strong>tag</strong> name to make it work.<br>So if we want our image to have that animation, we have to wrap our widget with a <strong>Hero</strong> widget.</p><p>I created a custom widget that we will use to move from the origin to destination</p><pre>class CustomLogo extends StatelessWidget {<br>  final double size;</pre><pre>CustomLogo({this.size = 200.0});</pre><pre><a href="http://twitter.com/override">@override</a><br>  Widget build(BuildContext context) {<br>    return Container(<br>      color: Colors.lightBlueAccent,<br>      width: size,<br>      height: size,<br>      child: Center(<br>        child: Image.asset(<br>          &quot;images/mario_logo.png&quot;,<br>          width: size,<br>          height: size,<br>        ),<br>      ),<br>    );<br>  }<br>}</pre><p>This is the image if you want to use</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/176/1*2vcx-MffMMyunJke2q66OQ.png" /><figcaption>mario_logo.png</figcaption></figure><p>Don’t forget to add it into the <strong>pubspec.yaml</strong> file</p><pre>assets:</pre><pre>- images/mario_logo.png</pre><p>After we have our <strong>child</strong> widget, we have to put it inside our <strong>Hero</strong> widget with a defined <strong>tag</strong> name, in this case I will use <strong><em>hero1</em></strong> as tag name.</p><pre>                Hero(<br>                    tag: &quot;hero1&quot;,<br>                    child: ClipOval(<br>                      child: CustomLogo(<br>                        size: 60.0,<br>                      ),<br>                    ),<br>                  ),</pre><p>As you can see in the code above, our <strong>CustomLogo</strong> is wrapped by <strong>ClipOval</strong> (To cut out our widget in a circular way) and also wrapped by the <strong>Hero.</strong></p><p>Now that we have our origin <strong>Hero</strong> , let’s go to call our destination page that contains the destination <strong>Hero</strong>:</p><pre>Navigator.push(<br>        context,<br>        MaterialPageRoute(<br>            fullscreenDialog: true, builder: (BuildContext context) =&gt; <strong>Page1()</strong>));</pre><p>Basically, after we press some button, we’ll call to the <strong>Navigator.push</strong> to go to the next page.</p><p>And this is our <strong>Page1 </strong>(destination page<strong>) </strong>widget.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0f1c474baf4aa85f75c6bfb15cd6eeba/href">https://medium.com/media/0f1c474baf4aa85f75c6bfb15cd6eeba/href</a></iframe><p>As you can see in the code above, we are using a our <strong>CustomLogo</strong> with a custom size , wrapped by a <strong>Hero</strong> with the same <strong>tag</strong> name as the origin “<strong><em>hero1”</em></strong></p><h3>Result</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/236/1*YEpunW0KrFrN4D5HVLMh8w.gif" /></figure><p>It is also possible to have animation for more than one element, that is, we can have more than one <strong>Hero</strong> per page, in the same way <strong>Hero</strong> origin and destination must have the same <strong>tag</strong> names.</p><p>In this case we will show a <strong>Hero</strong> image and a <strong>Hero</strong> text as they move towards the destination screen.</p><pre>Column(<br>                children: &lt;Widget&gt;[<br>                  Hero(<br>                    tag: &quot;hero1&quot;,<br>                    child: ClipOval(<br>                      child: CustomLogo(<br>                        size: 60.0,<br>                      ),<br>                    ),<br>                  ),<br>                  Hero(<br>                      tag: &quot;hero2&quot;,<br>                      child: Material(<br>                        color: Colors.transparent,<br>                        child: Text(<br>                          &quot;Sample Hero&quot;,<br>                          style: TextStyle(fontSize: 14.0, color:   Colors.black),<br>                        ),<br>                      ))<br>                ],<br>              )</pre><p>Calling our Page2</p><pre>Navigator.push(<br>        context,<br>        MaterialPageRoute(<br>            fullscreenDialog: true, builder: (BuildContext context) =&gt; <strong>Page2()</strong>));</pre><h3>Result</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/236/1*lJdbZYbYsQmSyzyWN7Ohtg.gif" /></figure><p>If you see this animation you notice a glitch in the <strong>Text</strong> widget transition, I think it’s a Flutter bug, but it can easily fixed by wrapping our <strong>Text</strong> widget origin and destination with the <strong>Material</strong> widget.</p><pre>Column(<br>                children: &lt;Widget&gt;[<br>                  Hero(<br>                    tag: &quot;hero1&quot;,<br>                    child: ClipOval(<br>                      child: CustomLogo(<br>                        size: 60.0,<br>                      ),<br>                    ),<br>                  ),<br>                  Hero(<br>                      tag: &quot;hero2&quot;,<br>                      child: Material(<br>                        color: Colors.transparent,<br>                        child: Text(<br>                          &quot;Sample Hero&quot;,<br>                          style: TextStyle(fontSize: 14.0, color: Colors.black),<br>                        ),<br>                      ))<br>                ],<br>              ),</pre><p><strong>Destination</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/abafc409a5e954a2db4dfd4af4104070/href">https://medium.com/media/abafc409a5e954a2db4dfd4af4104070/href</a></iframe><p><strong>Result</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/242/1*0_dTfdxRz0pp6PRzu8kP-A.gif" /></figure><p>Works better, right?</p><p>Something that many ask is if we can use <strong>Heroes </strong>using <strong>AlertDialog.</strong></p><p>This is possible, but to achieve this we have to create a custom <strong>PageRoute</strong>.</p><p><strong>Origin</strong></p><pre>Column(<br>                children: &lt;Widget&gt;[<br>                  Hero(<br>                    tag: &quot;hero1&quot;,<br>                    child: ClipOval(<br>                      child: CustomLogo(<br>                        size: 60.0,<br>                      ),<br>                    ),<br>                  ),<br>                  Hero(<br>                      tag: &quot;hero2&quot;,<br>                      child: Material(<br>                        color: Colors.transparent,<br>                        child: Text(<br>                          &quot;Sample Hero&quot;,<br>                          style: TextStyle(fontSize: 14.0, color: Colors.black),<br>                        ),<br>                      ))<br>                ],<br>              )</pre><p><strong>Destination Popup (after we press click in some button)</strong></p><pre>Navigator.push(<br>        context, HeroDialogRoute(builder: (BuildContext context) =&gt; return Center(<br>      child: AlertDialog(<br>        title: Hero(<br>            tag: &quot;hero2&quot;, child: Material(child: Text(&#39;You are my hero.&#39;))),<br>        content: Container(<br>          child: Hero(<br>              tag: &#39;hero1&#39;,<br>              child: CustomLogo(<br>                size: 300.0,<br>              )),<br>        ),<br>        actions: &lt;Widget&gt;[<br>          OutlineButton(<br>            onPressed: () =&gt; Navigator.of(context).pop(),<br>            child: Icon(Icons.close),<br>          ),<br>        ],<br>      ),<br>    )));</pre><p>You can see an error here, the <strong>HeroDialogRoute</strong> doesn’t exist , so we’ll have to create that custom route.</p><p>This is the code</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ec37575cad362b751e38814d90880bab/href">https://medium.com/media/ec37575cad362b751e38814d90880bab/href</a></iframe><h3>Result</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/244/1*bpGBp9U24nah0pq_6xvezg.gif" /></figure><p>Finally, we can also create personalized transitions, with the duration and animation that we like the most.</p><p>As we can see in the first example, the transition of the background screen is shown a little forced and the animation of the <strong>Heroes</strong> are shown very fast.</p><p>Now I going to create a <strong>Hero</strong> animation smoother and also with more duration.</p><p><strong>Origin</strong></p><pre>Column(<br>                children: &lt;Widget&gt;[<br>                  Hero(<br>                    tag: &quot;hero1&quot;,<br>                    child: ClipOval(<br>                      child: CustomLogo(<br>                        size: 60.0,<br>                      ),<br>                    ),<br>                  ),<br>                  Hero(<br>                      tag: &quot;hero2&quot;,<br>                      child: Material(<br>                        color: Colors.transparent,<br>                        child: Text(<br>                          &quot;Sample Hero&quot;,<br>                          style: TextStyle(fontSize: 14.0, color: Colors.black),<br>                        ),<br>                      ))<br>                ],<br>              )</pre><p><strong>Destination</strong></p><p>We’ll use the same <strong>Page1 </strong>widget as destination page.</p><p>Achieving a custom animation is related to the transaction of the <strong>PageRoute</strong>, we will show an example.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/abf23f4709c6a4478b3d9954895e8ba6/href">https://medium.com/media/abf23f4709c6a4478b3d9954895e8ba6/href</a></iframe><p>We use a <strong>PageRouteBuilder </strong>with an <strong>AnimatedBuilder</strong> as <strong>pageBuilder </strong>attribute, and inside the <strong>animatedBuilder</strong> we use the <strong>Opacity</strong> widget to display the page smoother, also we modified the <strong>transitionDuration </strong>to 600 milliseconds.</p><h3><strong>Final Result</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/240/1*IeAD2e0hM_QThzry3v1FMw.gif" /></figure><h3>Conclusion</h3><p>Flutter provides us with many tools and APIs for handling transitions and animations, later I will write some related posts about animations.</p><p>You can check the source code in my flutter-samples repo <a href="https://github.com/diegoveloper/flutter-samples"><strong>https://github.com/diegoveloper/flutter-samples</strong></a></p><h3>References</h3><p><a href="https://flutter.io/animations/hero-animations/">https://flutter.io/animations/hero-animations/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f1a083cb123a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter : Collapsing Toolbar — Sliver App Bar]]></title>
            <link>https://medium.com/@diegoveloper/flutter-collapsing-toolbar-sliver-app-bar-14b858e87abe?source=rss-496732f72ff1------2</link>
            <guid isPermaLink="false">https://medium.com/p/14b858e87abe</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Diego Velasquez]]></dc:creator>
            <pubDate>Tue, 10 Jul 2018 19:04:40 GMT</pubDate>
            <atom:updated>2018-07-11T05:42:41.477Z</atom:updated>
            <content:encoded><![CDATA[<p>The <strong>Collapsing Toolbar</strong> is UI component widely used in our applications today. It consists of displaying an image or background in the upper part of the screen, occupying a fixed space, so that later, by scrolling upwards, the content changes and becomes a navigation bar in <strong>iOS</strong> or toolbar in the case of <strong>Android</strong>.<br>Here I show you a visual example of how an interface looks using Collapsing Toolbar</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/244/1*kxT9EyxIJDS-vCiZASyWvg.gif" /></figure><p>In <strong>Android</strong> the <strong>CollapsingToolbar</strong> UI component is available within the design-support library, while in <strong>iOS</strong> there is no official UI component, but there are libraries that help us to do the same.</p><p>In order to do the same in <strong>Flutter</strong>, we need to use the <strong>Widget</strong> called <strong>SliverAppBar</strong> together with <strong>FlexibleSpaceBar</strong> as a child.</p><p>I’m going to show you a simple example</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c79755eadf553249f0e8e46e6483535a/href">https://medium.com/media/c79755eadf553249f0e8e46e6483535a/href</a></iframe><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/268/1*ytz2rpcRBuIwlRpjaFS51w.gif" /></figure><p>So far everything is fine, behaves as we want, with just a few lines of code :), however, I had a problem when using <strong>SliverAppBar</strong> along with TabBars.</p><p>I will add 2 tabs and we will see what happens.</p><p>This is the code</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5a2c7b0cd09d7e5a4187ef3e143e114b/href">https://medium.com/media/5a2c7b0cd09d7e5a4187ef3e143e114b/href</a></iframe><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/268/1*1NrXjq9ZJfjGz7W1-23slw.gif" /></figure><p>As we can see, the UI looks very bad, due to the fact the title does not reach the top bar, so it is crossed with the <strong>Tabs</strong>.</p><p>We are going to try to improve this design, for this I am going to remove the Tabs from the <strong>SliverAppBar</strong> and I will put them in another <strong>Sliver</strong>, the code would be as follows</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ccdf96d4542ec2234b18ba6919993634/href">https://medium.com/media/ccdf96d4542ec2234b18ba6919993634/href</a></iframe><h4>Result</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/268/1*Nyd1caknnJPsPGwYmWc2rA.gif" /></figure><p>It’s better, right? but we have a problem, at the time of scrolling up, the <strong>Tabs</strong> are not fixed and disappears, this is not what we are looking for, so to solve this, we must use the <strong>SliverPersistentHeader</strong> and create a <strong>delegate</strong> subclass of <strong>SliverPersistentHeaderDelegate</strong>, as follows</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ae6aecb42cedc626615849cf8e8c7717/href">https://medium.com/media/ae6aecb42cedc626615849cf8e8c7717/href</a></iframe><h3>Final Result</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/268/1*xtROWw7cWRrK5b7tPbw2mg.gif" /></figure><h3>Conclusion</h3><p>Many times we encounter some problems that we think we can’t do in Flutter, but all we have to do is read the documentation step by step.</p><p>You can check the source code in my flutter-samples repo <a href="https://github.com/diegoveloper/flutter-samples"><strong>https://github.com/diegoveloper/flutter-samples</strong></a></p><h3>References</h3><p><a href="https://docs.flutter.io/flutter/material/SliverAppBar-class.html">https://docs.flutter.io/flutter/material/SliverAppBar-class.html</a><br><a href="https://docs.flutter.io/flutter/material/FlexibleSpaceBar-class.html">https://docs.flutter.io/flutter/material/FlexibleSpaceBar-class.html</a><br><a href="https://docs.flutter.io/flutter/widgets/SliverPersistentHeaderDelegate-class.html">https://docs.flutter.io/flutter/widgets/SliverPersistentHeaderDelegate-class.html</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14b858e87abe" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>