Flutter: Text overlapping with Positioned widget in Stack layout

Flutter: Text overlapping with Positioned widget in Stack layout
typescript
Ethan Jackson

I'm working on a Flutter layout where I have a list of transport modes (like Walk, Car, Bus, Train), and I’m placing a profile avatar on top using a Stack with a Positioned widget
Here the profile avatar is not inside the 1th row
This is the Sample UI

Stack( children: [ Container( color: Colors.grey[300], padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text("Walk"), Text("Car"), Text("Bus"), Text("Train"), ], ), ), Positioned( top: 0, right: 0, child: CircleAvatar( radius: 24, child: Icon(Icons.person), ), ), ], )

Everything works fine until the text becomes too long, like in this case
If the text is too long this is how it paints problematic UI

I tried manually wrapping the text in sizedbox with some fixed width then there is not overlapping.
But this is not working for all the cases.

Stack( children: [ Container( color: Colors.grey[300], padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Row( children: [ Icon(Icons.directions_walk), SizedBox(width: 8), // Manually restrict text width to avoid overlap SizedBox( width: 80, // <-- hardcoded width child: Text("Walk Walk Walk"), ), ], ), Row( children: [ Icon(Icons.directions_car), SizedBox(width: 8), Text("Car"), ], ), Row( children: [ Icon(Icons.directions_bus), SizedBox(width: 8), Text("Bus"), ], ), Row( children: [ Icon(Icons.train), SizedBox(width: 8), Text("Train"), ], ), ], ), ), Positioned( top: 0, right: 0, child: CircleAvatar( radius: 24, child: Icon(Icons.person), ), ), ], )

Is there a better way to lay this out so the Positioned widget doesn't interfere with the text layout below — without hardcoding widths

Answer

I would suggest to follow this 2 steps:

  1. Place the Text("Walk Walk Walk") widget inside an Expanded widget:

    Expanded(child: Text("Walk Walk Walk")),
  2. Add a SizedBox with a width of 32 at the end of the Row:

Row( children: [ Icon(Icons.directions_walk), SizedBox(width: 8), // Expanded will use all the remaining space in the row Expanded(child: Text("Walk Walk Walk")), SizedBox(width: 32), ], );

Why '32'? Your CircleAvatar has a radius of 24, so its width is 48. And you added a padding of 16 to your Column. So if you subtract 48 - 16 = 32. This is the needed space to avoid the overlapping.

This way you avoid overlapping while while taking advantage of all the remaining space, no matter the size of the screen:

Narrow screen example

Wide screen example

Also, you should consider creating a variable for the avatar radius and the column padding, so that you can set the SizedBox width in the following way and avoid hardcoding values:

Row( children: [ Icon(Icons.directions_walk), SizedBox(width: 8), // Expanded will use all the remaining space in the row Expanded(child: Text("Walk Walk Walk")), SizedBox(width: 2 * avatarRadius - padding), ], );

Hope this help!

Related Articles