<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josué Martínez</title>
    <description>The latest articles on DEV Community by Josué Martínez (@josuestuff).</description>
    <link>https://dev.to/josuestuff</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1626425%2F6826a3c7-bcf8-4004-8162-038a207c0987.jpg</url>
      <title>DEV Community: Josué Martínez</title>
      <link>https://dev.to/josuestuff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josuestuff"/>
    <language>en</language>
    <item>
      <title>Building a custom dropdown in Flutter</title>
      <dc:creator>Josué Martínez</dc:creator>
      <pubDate>Mon, 09 Sep 2024 02:30:02 +0000</pubDate>
      <link>https://dev.to/josuestuff/building-a-custom-dropdown-in-flutter-55h9</link>
      <guid>https://dev.to/josuestuff/building-a-custom-dropdown-in-flutter-55h9</guid>
      <description>&lt;p&gt;Is been almost 3 months since I started working as a Flutter developer in a small startup company and a been learning a lot. So, as usual, today I wanna share one of the things I learned in the past few months: dealing with custom dropdowns.&lt;/p&gt;

&lt;p&gt;Since we don't use Flutter's stock dropdowns at work (either Material or Cupertino), I needed to figure out how to make a custom one at least 2 times in the past months and I'm pretty sure I'm not the only one. That said, let's move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  First things first
&lt;/h2&gt;

&lt;p&gt;In this post I'll use two key widgets to build the dropdown, so before going into the code, let's understand these widgets.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;CompositedTransformTarget&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This one is really important to simplify the task and the docs says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When this widget is composited during the compositing phase (which comes after the paint phase, as described in &lt;code&gt;WidgetsBinding.drawFrame&lt;/code&gt;), it updates the link object so that any &lt;code&gt;CompositedTransformFollower&lt;/code&gt; widgets that are subsequently composited in the same frame and were given the same &lt;code&gt;LayerLink&lt;/code&gt; can position themselves at the same screen location.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short: this widget will hold the global position of any child widget and we can use the &lt;code&gt;CompositedTransformFollower&lt;/code&gt; widget to position any other widget in the same place by using the same &lt;code&gt;LayerLink&lt;/code&gt;. So, I assume you can image how we're gonna use it: to position the "attached" section of the dropdown right below the other one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;OverlayPortal&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Right, so, we already solved a problem, but we have another one: working with the raw overlay API is a pain and I know that by experience 💀. So... There's a better and simpler way to put widgets on top of others? Of course: &lt;code&gt;OverlayPortal&lt;/code&gt;, which is part of the overlay API, but way more simple and so we're gonna use it to build the dropdown.&lt;/p&gt;

&lt;p&gt;Also, in case you think &lt;code&gt;Stack&lt;/code&gt; would do the job too, please don't do that. I know Stack can also position widgets on top of others, but final code will look very "tricky" as you have to put the widgets in way that they will be for sure on top of the others, leading you to write an absolute mess of code, making it a bit hard to read and work on later.&lt;/p&gt;

&lt;p&gt;The other problem with &lt;code&gt;Stack&lt;/code&gt; is that it will lead you to use &lt;code&gt;Positioned&lt;/code&gt;, forcing you to hardcode values, which isn't good if you want your app to (and it should) be responsive no matter if it will run only on smartphones. That method also doesn't take in consideration growable lists, which is a very common pattern in app designs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's start already
&lt;/h2&gt;

&lt;p&gt;Alright, so the process is pretty simple, first we need a &lt;code&gt;LayerLink&lt;/code&gt; and a &lt;code&gt;OverlayPortalController&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// This controller doesn't have a `dispose` method,&lt;/span&gt;
&lt;span class="c1"&gt;// so you can use an `StatelessWidget`&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OverlayPortalController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LayerLink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, we place our &lt;code&gt;OverlayPortal&lt;/code&gt; widget anywhere we need it in our &lt;code&gt;build&lt;/code&gt; method or somewhere else:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;OverlayPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;overlayChildBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can imagine, the &lt;code&gt;overlayChildBuilder&lt;/code&gt; in &lt;code&gt;OverlayPortal&lt;/code&gt; takes a builder function that will be use to build the widget that will be on top of all our other widgets, allowing us to write a separated widget to keep this as clean as possible.&lt;/p&gt;

&lt;p&gt;Alright, let's keep going and add a child to the &lt;code&gt;OverlayPortal&lt;/code&gt;, which will be the interactive section, so we also need to wrap it with &lt;code&gt;CompositedTransformTarget&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;OverlayPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;overlayChildBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Toggle dropdown'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, let's make the overlay child follow the same positioning as the button:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;OverlayPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;overlayChildBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformFollower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="c1"&gt;// Ensure to use the same `LayerLink`&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Toggle dropdown'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that's it, we have the base implementation, but if you try that right now, you will notice some issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;Placeholder&lt;/code&gt; is on top of the button&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Placeholder&lt;/code&gt; covers too much space&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first issue is actually pretty easy to fix: just set the &lt;code&gt;targetAnchor&lt;/code&gt; property in &lt;code&gt;CompositedTransformFollower&lt;/code&gt; to &lt;code&gt;Alignment.bottomLeft&lt;/code&gt;. Like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;OverlayPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;overlayChildBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformFollower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="c1"&gt;// Ensure to use the same `LayerLink`&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;targetAnchor:&lt;/span&gt; &lt;span class="n"&gt;Alignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bottomLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;   &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Toggle dropdown'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now the other issue is a &lt;em&gt;bit&lt;/em&gt; more complicated to fix. But let's understand why does that happens: anything that belongs into an overlay in Flutter essentially uses a whole new &lt;code&gt;BuildContext&lt;/code&gt;, which also means the very top widget in that widget tree will be enforced to be as the same size of the viewport and that cannot be changed.&lt;/p&gt;

&lt;p&gt;So, to fix that, we need a widget that takes all that available space and allows it's child to be of any desired size. There are few widgets that fits that condition, but in this example we're gonna use &lt;code&gt;UnconstrainedBox&lt;/code&gt; to fix this problem and then we can finally use any sizing widget, a &lt;code&gt;SizedBox&lt;/code&gt; for example, to limit the size of the dropdown widget.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="n"&gt;OverlayPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;overlayChildBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UnconstrainedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformFollower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="c1"&gt;// Ensure to use the same &lt;code&gt;LayerLink&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;targetAnchor:&lt;/span&gt; &lt;span class="n"&gt;Alignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bottomLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CompositedTransformTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;link:&lt;/span&gt; &lt;span class="n"&gt;_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Toggle dropdown'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;),&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Almost perfect&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Despite this implementation for dropdowns is actually really good and simple, there's still one problem: what if there's insufficient space to show the dropdown?&lt;/p&gt;

&lt;p&gt;Let's say you have a dynamic layout where things can change size or position. In that case, your dropdown might not have enough space to show and can clip out of bounds, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8bsthtnocw6v1lfm7mz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8bsthtnocw6v1lfm7mz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an important problem because user then couldn't have access to the dropdown menu, leaving them with a really bad UX. And, to be honest, I haven't found an &lt;em&gt;elegant&lt;/em&gt; solution to this yet either using external packages or not (maybe &lt;code&gt;visibility_detector&lt;/code&gt; could help but, again, I haven't tried yet).&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Well that's all for today, hope you enjoyed it all! If you liked this, let a comment or react in this post :)&lt;/p&gt;

&lt;p&gt;And, of course, here's the entire (but slightly more elaborated) code of this article: &lt;a href="https://gist.github.com/Miqueas/4d0b92a15c0cc24fee6ef389250ab027" rel="noopener noreferrer"&gt;https://gist.github.com/Miqueas/4d0b92a15c0cc24fee6ef389250ab027&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have a nice day and see you later!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Learning about CustomPaint in Flutter</title>
      <dc:creator>Josué Martínez</dc:creator>
      <pubDate>Sun, 23 Jun 2024 23:09:54 +0000</pubDate>
      <link>https://dev.to/josuestuff/learning-about-custompaint-in-flutter-4j69</link>
      <guid>https://dev.to/josuestuff/learning-about-custompaint-in-flutter-4j69</guid>
      <description>&lt;p&gt;Something like a week ago I started to research about "how I can manually draw things in the Flutter canvas" and found information about &lt;code&gt;CustomPaint&lt;/code&gt; and &lt;code&gt;CustomPainter&lt;/code&gt;, which seems to be the main Flutter mechanism to allow devs draw specific things.&lt;/p&gt;

&lt;p&gt;I'm not sure if there're more options or alternatives to achieve that, so for now let's just talk about my experience with Flutter's &lt;code&gt;CustomPaint&lt;/code&gt; widget.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flutter art workshop, an analog perspective
&lt;/h2&gt;

&lt;p&gt;Since the very first moment I started to learn Flutter, I inmediately noticed that it is, essentially, just an OpenGL canvas with a bunch of abstractions. I personally don't like that, not because of the abstractions themselves, but because using an OpenGL canvas doesn't feel... Native... Like, it's really easy to notice that.&lt;/p&gt;

&lt;p&gt;And you may think: "Well, yeah, but if you think about that, every user interface is just an intangible abstraction, so... Who cares?". And yeah, you're right and I also agree with that, it's just a personal opinion and I've been learning how that approach for making user interfaces brings some benefits.&lt;/p&gt;

&lt;p&gt;With that in mind, I ended up to the conclusion that Flutter it's likely an art workshop: it gives you canvas and a bunch of different brushes and tools to draw interfaces in a fast, simple and easy way. With this perspective, using an OpenGL canvas makes much more sense and helps bit to understand how &lt;code&gt;CustomPaint&lt;/code&gt; works and it's more easy to explain it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alright, let's move on a bit more
&lt;/h2&gt;

&lt;p&gt;So, you are working on a Flutter project and there's something specific you want to do, but Flutter doesn't have a widget for that and there's only one solution: create it by yourself. Well, the way to do that is by using &lt;code&gt;CustomPaint&lt;/code&gt;, a widget that gives you direct access to the canvas, allowing you to draw things, but with one requirement: you need to give it a &lt;code&gt;CustomPainter&lt;/code&gt;, which is basically Flutter telling you "Fine, you can draw here, but you must give an specialized artist for this very specific job!".&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a &lt;code&gt;CustomPainter&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;At this point, you may be wondering what's a &lt;code&gt;CustomPainter&lt;/code&gt; and how to create them, because if you try giving a literal &lt;code&gt;CustomPainter&lt;/code&gt; to a &lt;code&gt;CustomPaint&lt;/code&gt;, you'll get an error. That's because &lt;code&gt;CustomPainter&lt;/code&gt; is an abstract class and we have to create a class that &lt;code&gt;extends&lt;/code&gt; from &lt;code&gt;CustomPainter&lt;/code&gt; instead. So, let's make it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WavePainter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Canvas&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;shouldRepaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="n"&gt;oldDelegate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let me explain this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our class is named &lt;code&gt;WavePainter&lt;/code&gt; because we're going to make a simple audio waveform widget (as in the banner of this article)&lt;/li&gt;
&lt;li&gt;All classes that &lt;code&gt;extends&lt;/code&gt; from &lt;code&gt;CustomPainter&lt;/code&gt; must override 2 methods:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;paint&lt;/code&gt;: this one is where we're going to draw&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shouldRepaint&lt;/code&gt;: and this one handles if &lt;code&gt;paint&lt;/code&gt; should be called again&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty simple, right? The &lt;code&gt;paint&lt;/code&gt; methods recieves a &lt;code&gt;Canvas&lt;/code&gt; and a &lt;code&gt;Size&lt;/code&gt; object for the drawing stuff and &lt;code&gt;shouldRepaint&lt;/code&gt; recieves an old version of our &lt;code&gt;CustomPainter&lt;/code&gt; to check for changes and, if so, return true to tell Flutter to re&lt;code&gt;paint&lt;/code&gt; the widget, but we usually do this only if our widget has mutable data that is expected to change during the lifetime of our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting to draw
&lt;/h2&gt;

&lt;p&gt;Alright, so our &lt;code&gt;CustomPainter&lt;/code&gt; looks good so far, we can already give it to a &lt;code&gt;CustomPaint&lt;/code&gt;, however, it will not draw anything because we haven't code what to draw yet, so let's start by creating a &lt;em&gt;brush&lt;/em&gt; for our drawing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WavePainter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Canvas&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The Paint class is essentially a brush, so...&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="c1"&gt;// We set the color,&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xFFFAFAFA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;// the thickness of the line&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strokeWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
      &lt;span class="c1"&gt;// and how we want them to end&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strokeCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StrokeCap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;round&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;shouldRepaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="n"&gt;oldDelegate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you should check out the &lt;a href="https://api.flutter.dev/flutter/dart-ui/Paint-class.html"&gt;API reference for the Paint&lt;/a&gt; class to know what else you can do with it. Now, our brush is ready to use, so it's time to finish our drawing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WavePainter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Canvas&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;brush&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strokeWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strokeCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StrokeCap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;round&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextDouble&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;drawLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;brush&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;shouldRepaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="n"&gt;oldDelegate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we put that inside of a &lt;code&gt;CustomPaint&lt;/code&gt;, we should get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7admi4xkf213jz4d2p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7admi4xkf213jz4d2p8.png" alt="Figure 1: preview of the final result" width="376" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding what's going on
&lt;/h2&gt;

&lt;p&gt;Now, again, I'm gonna explain these changes a bit more, but first, we need to understand how exactly positioning works in this case, which is pretty simple because we can understand it by just looking at this image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91b4qor2j5223vszv53m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91b4qor2j5223vszv53m.jpg" alt="Figure 2: how positioning works on the given canvas" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we start drawing at the top left corner of the given canvas, so if we don't want to draw outside of it, we should use positive numbers. That said, we will want to find the vertical center of that canvas and that's exactly what we did with &lt;code&gt;size.height / 2&lt;/code&gt;, we're gonna use that number for both: positioning our bars and limit it's size.&lt;/p&gt;

&lt;p&gt;By default, all custom paints gets a canvas of 300x300, but we can change that by putting our custom paint into another widget that could help to set a different size. In this case, I created a canvas of 400x100 by putting my custom paint inside of a &lt;code&gt;Container&lt;/code&gt;, so our vertical center is 50 (unless we change the height of the &lt;code&gt;Container&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;That said, how we're gonna use that number as the limit of our bars? Well, that's pretty simple and we already did it in this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextDouble&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see, since &lt;code&gt;nextDouble&lt;/code&gt; will always return a number between 0.0 and 1.0, mutiplying that result by the vertical center will never exceed half the height of the canvas, so it's perfectly fine to do that. Now this section in the code we wrote makes more sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;drawLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verticalCenter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="n"&gt;brush&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;drawLine&lt;/code&gt; requires an starting point and an end point for drawing lines, so we're doing this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftcg183wlwm48kbymgpt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftcg183wlwm48kbymgpt.jpg" alt="Figure 4: helper for vertical positioning" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty simple, right? Now, you might be thinking: "What about &lt;code&gt;shift&lt;/code&gt;? What it does?". Well, &lt;code&gt;shift&lt;/code&gt; is even more easy: it controls the horizontal position of our bars. Since we're not only putting them side by side, but also leaving a small space between them, we set &lt;code&gt;shift&lt;/code&gt; to the width of the line (3) + space we want to have between bars (also 3) and we just keep incrementing it after every use.&lt;/p&gt;

&lt;p&gt;Finally, to prevent our drawing to go out of the size of the given canvas, we put an additional condition to our &lt;code&gt;for&lt;/code&gt; loop: &lt;code&gt;shift &amp;lt; size.width&lt;/code&gt;. With that simple condition, no matter the width of the given canvas or how much data we have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;To be honest, learning how to do this was a really cool thing, I enjoyed the process and had a fun moment so far, despite I wasn't able to implement it in the project I'm working on.&lt;/p&gt;

&lt;p&gt;Here is the full code for this article: &lt;a href="https://gist.github.com/Miqueas/b66297d8de4a29000e9cb4d3f9cdc3f5"&gt;https://gist.github.com/Miqueas/b66297d8de4a29000e9cb4d3f9cdc3f5&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyways, I hope you enjoyed this too, feel free to share, have a nice day and see you another day 👋.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ui</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>OverflowBox and videos in Flutter</title>
      <dc:creator>Josué Martínez</dc:creator>
      <pubDate>Fri, 14 Jun 2024 14:45:51 +0000</pubDate>
      <link>https://dev.to/josuestuff/overflowbox-and-videos-in-flutter-1kk8</link>
      <guid>https://dev.to/josuestuff/overflowbox-and-videos-in-flutter-1kk8</guid>
      <description>&lt;p&gt;Recently I was working on something with Flutter when I encountered with a small problem: how can I make a video to fill up all the available space inside a Container widget?&lt;/p&gt;

&lt;p&gt;Well, today I’m gonna explain how I did it and how the &lt;em&gt;&lt;a href="https://docs.flutter.dev/ui/layout/constraints"&gt;“Understanding constraints”&lt;/a&gt;&lt;/em&gt; Flutter docs article helped me in that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;OverflowBox&lt;/code&gt; widget
&lt;/h2&gt;

&lt;p&gt;I’m new in the Flutter world, so I usually have to deal with weird/strange/unexpected results while using it because I don’t have too much experience. But recently I found an article (mentioned earlier) about how constraints works in Flutter, written by the official Flutter development team. That article helped me a lot and was like a revelation, because it says a lot of important stuff to take in consideration while working with Flutter and since I didn’t learned Flutter by reading the documentation, it was really useful for me.&lt;/p&gt;

&lt;p&gt;It was in that article where I found the &lt;code&gt;OverflowBox&lt;/code&gt; widget, which as it’s name suggests, is a widget that allows it’s inner child to overflow without getting the typical “overflow error” in Flutter. In the moment, I didn’t pay too much attetion to it because it didn’t sound too interesting to me and wasn’t able to imagine a situation where I would need to use it. Except that… It didn’t take too much time for me to found a use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Videos and the &lt;code&gt;AspectRatio&lt;/code&gt; widget
&lt;/h2&gt;

&lt;p&gt;As I said at the start, I was making something in Flutter (a fixed size widget where to put a widget for playing videos) and everytthing was going good until I realized that the rounded corners I made for the widget weren’t working. I spent a while trying to figure out what the heck was going on, because not only the rounded corners weren’t working , but also the video had a different size. After a couple of long minutes, I started to suspect about what was going on: I saw the AspectRatio widget… And decided to put a background color to the Container where I was making all of that and… I saw the problem.&lt;/p&gt;

&lt;p&gt;Look, when we put something into an &lt;code&gt;AspectRatio&lt;/code&gt; widget, it will do pretty much what the name suggests: ensure the child widget keeps the given aspect ratio, so if we put that widget inside of another widget that has a different aspect ratio, it will do something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvjfgosetl4957ayj1gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvjfgosetl4957ayj1gw.png" width="247" height="244"&gt;&lt;/a&gt;The AspectRatio widget with the video is inside of a 200x200 Container, the yellow background helps to notice what’s going on.&lt;/p&gt;

&lt;p&gt;As we can see, the widget does the job very well and the result is the expected… Which is kinda obvious by just looking at the name of the widget, but for me that wasn’t the case. And the code for that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amber&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;AspectRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;aspectRatio:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;VideoPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, using the &lt;code&gt;AspectRatio&lt;/code&gt; widget with videos makes a lot of sense, but… I didn’t want this result… I wanted to fill the entire space with the video, no matter if that means that it will be cropped off.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution…?
&lt;/h2&gt;

&lt;p&gt;So, I was thinking… “How can I solve this?”… And then, all of the sudden, I just remembered that I saw a widget in an article that I readed recently… That’s right, the &lt;code&gt;OverflowBox&lt;/code&gt; widget I just saw a couple of days ago in the &lt;em&gt;&lt;a href="https://docs.flutter.dev/ui/layout/constraints"&gt;“Understanding constraints”&lt;/a&gt;&lt;/em&gt; article.&lt;/p&gt;

&lt;p&gt;There was no time to think twice, I started to code and… It didn’t work. But, it was my fault, because it didn’t set how I wanted the child to overflow inside the &lt;code&gt;OverflowBox&lt;/code&gt; widget, so I fixed that and there we go, problem… Solved?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0gvu5aozixa3zfhb8z8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0gvu5aozixa3zfhb8z8.png" width="396" height="236"&gt;&lt;/a&gt;As you can see, that video is definitely NOT an 200x200 box as it’s parent…&lt;/p&gt;

&lt;p&gt;Well, what’s going on? It still looks to have the same aspect ratio, but bigger… And we can tell the &lt;code&gt;OverflowBox&lt;/code&gt; is doing the job because we can’t see the yellow background… And the code is correct as we just wrapped the &lt;code&gt;AspectRatio&lt;/code&gt; with the &lt;code&gt;OverflowBox&lt;/code&gt;, that should do the job, right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amber&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;OverflowBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;maxWidth:&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;maxHeight:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;AspectRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;aspectRatio:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;VideoPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well… No. This result is expected and should not be surprising if we pay attention to the Flutter API: almost all widgets does only 1 thing and almost all of them don’t crop other widgets unless we specifically tell them to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s fix this already!
&lt;/h2&gt;

&lt;p&gt;Alright, now it’s more clear what we need to do, so let’s “fix” the code above by setting the &lt;code&gt;clipBehavior&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;clipBehavior:&lt;/span&gt; &lt;span class="n"&gt;Clip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;antiAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amber&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;OverflowBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;maxWidth:&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;maxHeight:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;AspectRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;aspectRatio:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;VideoPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, finally, there we go, problem solved:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ynx0nl58gngeoampram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ynx0nl58gngeoampram.png" width="249" height="240"&gt;&lt;/a&gt;As you can see, that video is definitely NOT in a 200x200 aspect ratio as it’s parent…&lt;/p&gt;

&lt;p&gt;Now, this can also be done with &lt;code&gt;ClipRect&lt;/code&gt;, but &lt;code&gt;Container&lt;/code&gt;let’s us set the width, height, background color and we can even do the same thing of clipping the content… But also making nice rounded corners by just adding a single line of code!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftoe0lvtvc7hjaimqacyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftoe0lvtvc7hjaimqacyo.png" width="233" height="246"&gt;&lt;/a&gt;So elegant!&lt;/p&gt;

&lt;p&gt;And that’s just…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;clipBehavior:&lt;/span&gt; &lt;span class="n"&gt;Clip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;antiAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),),&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;OverflowBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;maxWidth:&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;maxHeight:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;AspectRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;aspectRatio:&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;VideoPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  “Nice, I’m gonna use it with images!”
&lt;/h2&gt;

&lt;p&gt;Now, hold on right there… Sure, you can do that I guess, however, you may not need it. Why? Well, that’s pretty simple: the Image widget already has mechanisms to achieve either the same, similar or better results. So… There’s no need to do that, you can just try playing around with Image and other widgets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There’s not so much to say, I love when I learn something new like that because is something that came from my mind: not asking, not googling, just straightforward knowledge that I already have but only pops out in the best moment where I need it.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this pretty simple article, I just wanted to share a small experience in my path learning Flutter. This was originally posted on my personal &lt;a href="https://t.me/JosueStuff"&gt;Telegram channel&lt;/a&gt; in a more casual way, so if you want to read it, &lt;a href="https://t.me/JosueStuff/1118"&gt;here it is&lt;/a&gt; where it started.&lt;/p&gt;

&lt;p&gt;Also, if you want the full code, you can get it &lt;a href="https://gist.github.com/Miqueas/c1c268e7f2da5d94fc3b81914ce2cb4b"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have a nice day :)&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ui</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
