Flutter Web and Parallax
Tags: flutter, productivity, webdev, dart
Published: 2020-04-05 10:57:25

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:paragraph -->
<p>We have a parallax webpage on the website (made with Flutter Web). This page comprises of 3 sections&nbsp;:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Image section</li><li>Section One (What you need to know section)</li><li>Section Two (Ways we are uniting against COVID)</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>The root of our page is comprised of a <strong>Stack</strong> widget..The children of this widget is basically, above three sections…</p>
<!-- /wp:paragraph -->

{% youtube 3R3VZnUbMfY %}

####Article here: https://flatteredwithflutter.com/flutter-web-parallax/

<!-- wp:heading {"level":4} -->
<h4>Image Section…</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This is basically an image, now as we scroll down, we need to enable the parallax effect….with the following steps:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Set the image’s <strong>width</strong> and <strong>height</strong> equal to the screen’s width and height…</li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>This ensures that the image covers entire screen…</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">Image.asset(<br>     WebAssets.socialDistance.assetName,<br>     fit: BoxFit.fitWidth,<br>     width: _imageWidth,<br>     height: _imgHeight,<br>)</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>2. Create a <a href="https://api.flutter.dev/flutter/widgets/ListView-class.html" rel="noreferrer noopener" target="_blank"><strong>ListView</strong></a> widget and pass in the stack as one of the child.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, inside this listview, the first child is a <a href="https://api.flutter.dev/flutter/widgets/SizedBox-class.html" rel="noreferrer noopener" target="_blank"><strong>SizedBox,</strong></a> the height of this SizedBox is equal to the screen’s height…</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note&nbsp;: This is an important step and done, as the root widget is a Stack…</p></blockquote>
<!-- /wp:quote -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">ListView(<br>    cacheExtent: 100.0,<br>    addAutomaticKeepAlives: false,<br>    controller: _scrollController,<br>    children: &lt;Widget&gt;[<br>        SizedBox(height: _imgHeight),<br>    ],<br>),</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Properties of ListView&nbsp;:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>addAutomaticKeepAlives</strong>&nbsp;: false</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>By default, this is set to <strong>true</strong>, meaning that the children would preserve their state, otherwise they are garbage collected...</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We set this to false, meaning the children will be garbage collected depending on the <strong>cacheExtent</strong> property we set..</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>cacheExtent</strong>&nbsp;: 100.0</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>As per the documentation&nbsp;:</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>The <a href="https://api.flutter.dev/flutter/widgets/ListView/cacheExtent.html" rel="noreferrer noopener" target="_blank">cacheExtent</a> describes how many pixels the cache area extends before the leading edge and after the trailing edge of the viewport.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p><strong>controller</strong>&nbsp;: We need to track the scrolling portion of the user, hence introducing <a href="https://api.flutter.dev/flutter/widgets/ScrollController-class.html" rel="noreferrer noopener" target="_blank"><strong>ScrollConrollers</strong></a>..</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Using <strong>scrollcontrollers</strong>, we can determine the <strong>current scroll position</strong> or offset..</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To do so, we need to wrap our Stack with another widget called <a rel="noreferrer noopener" href="https://api.flutter.dev/flutter/widgets/NotificationListener-class.html" target="_blank"><strong>NotificationListener</strong></a><strong>.</strong></p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">NotificationListener&lt;T extends Notification&gt; class</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>As per the documentation,&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>A widget that listens for <a href="https://api.flutter.dev/flutter/widgets/Notification-class.html" rel="noreferrer noopener" target="_blank">Notification</a>s bubbling up the tree.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Notifications will trigger the <a href="https://api.flutter.dev/flutter/widgets/NotificationListener/onNotification.html" rel="noreferrer noopener" target="_blank">onNotification</a> callback only if their <a href="https://api.flutter.dev/flutter/dart-core/Object/runtimeType.html" rel="noreferrer noopener" target="_blank">runtimeType</a> is a subtype of <code>T</code>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>Our stack is wrapped with a <strong>NotificationListener</strong> of type <a rel="noreferrer noopener" href="https://api.flutter.dev/flutter/widgets/ScrollNotification-class.html" target="_blank"><strong>ScrollNotification</strong></a>.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">NotificationListener&lt;ScrollNotification&gt;(<br>    onNotification: _handleScrollNotification,<br>    child: Stack(),<br>)</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>The callback for this listener is <code>_handleScrollNotification</code> which returns a boolean..</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Inside this listener, we get the current scroll offset of the user..</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">bool _handleScrollNotification(ScrollNotification notification) {
    if (notification is ScrollUpdateNotification) {
      _currOffset = notification.metrics.pixels;
    }
 return false;
}</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This offset (<code>_currOffset</code>), which is set from the listener, is used to move our first image section…..</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>(Prev. Image Section…..)</strong></p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">Image.asset(<br>     WebAssets.socialDistance.assetName,<br>     fit: BoxFit.fitWidth,<br>     width: _imageWidth,<br>     height: _imgHeight,<br>)</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><strong>(New image section…)</strong></p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">Positioned(<br>  top: -0.25 * _currOffset, // -ve as we want to scroll upwards<br>     child: Image.asset(<br>     WebAssets.socialDistance.assetName,<br>     fit: BoxFit.fitWidth,<br>     width: _imageWidth,<br>     height: _imgHeight,<br>  ),<br>),</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Notice, the <code>_currOffset</code> here is multiplied by a negative number…Basically this is, as we want to move the image upwards (like what is needed for parallax)…</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Pss: The number itself depends on your parallax effect. <strong>(for me it was 0.25)</strong></p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p><strong>Don’t forget to dispose off your scroll controller…..</strong></p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:heading {"level":4} -->
<h4>Section One &amp; Section&nbsp;Two…</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In the image section, we introduced a listview…</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We simply add the sections one and two, as children of the listview..</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">ListView(<br>    cacheExtent: 100.0,<br>    addAutomaticKeepAlives: false,<br>    controller: _scrollController,<br>    children: &lt;Widget&gt;[<br>         SizedBox(height: _imgHeight), // IMP STEP 1..<br>         InfoRow(<br>           sectionText: ParallaxConstants.whatUKnow,<br>         ),<br>         InfoRow(<br>           sectionText: ParallaxConstants.united,<br>         ),        <br>    ],<br>),</pre>
<!-- /wp:preformatted -->

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Hosted URL&nbsp;: <a href="https://fir-signin-4477d.firebaseapp.com/#/" rel="noreferrer noopener" target="_blank">https://fir-signin-4477d.firebaseapp.com/#/</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><a href="https://github.com/AseemWangoo/experiments_with_web" rel="noreferrer noopener" target="_blank">Source code for Flutter Web App..</a></p></blockquote>
<!-- /wp:quote -->

{% youtube 3R3VZnUbMfY %}