How to Create Separators for Rows and Columns
We've likely come across the ListView.separated(), which lets us add a separator to each item in List. But what if we want to have this similar behaviour in a row or column?
If you've been developing a Flutter app for some time, you've likely come across the ListView
widget. The ListView
API provides a useful feature called ListView.separated(), which lets you add a separator to each item, similar to the ItemDecoration in RecyclerView in Android.
But what if we want to have this similar behaviour in a row or column? How do we add a separator to it?
Note: From this point forward, a Column will be used as an example. However, the concept applies to Row as well.
Let's say we have a design like this.
There are several ways to achieve it.
Approach 1
This approach is easy to read, but it requires a lot of duplication of SizedBox(height: 8.0)
after each widget. Additionally, when we want to add a new Text()
widget, we need to remember to add SizedBox()
as well.
Approach 2
We use this approach when we have a list of text. Although it removes duplication, it can suffer from readability issues. For example, it is not always clear why SizedBox(height: 8.0)
was added.
Approach 3
This solution fixes the problems from both approaches 1 and 2. However, in my opinion, it seems hacky and misleading because it uses Padding
to fix the separator issue. Therefore, I would recommend using it as a last resort.
Remember, all of the above approaches work; however, each has its own issues with readability, reusability, and maintainability.
A Better Way 🛣️
To address all of these issues, we can create a wrapper called separator
as an extension method on Iterable<Widget>
, like this:
In this extension, we are using generators to easily yield our separator element
after each item.
Yay!! We finally have a use case for generators.
(I have a few more use cases for generators. If you would like me to cover them in the next post, please let me know in the comments.)
We will now use this extension method with the above approaches 1 and 2, as shown below:
The separators
method removes duplication and improves readability by indicating that this widget will be used as a separator, similar to what we have in ListView.separator()
.
The other reason why I like this extension approach is that you can put things in between the widgets as well.
You can use this extension on any widget that has children of List<Widget>
. For example, you can use it on Wrap
and Stack
, or any other multi-child layout widgets.
What about performance? 🧪
Isn't it unnecessary to create this many lists just to avoid duplication and improve readability?
My argument is that if the list has only 10-20 items, then it won't have any issues. We can safely use the separator approach.
However, if the list contains more than 20-30 items, it is better to use a ListView
. This is because a ListView
is scrollable and performs better. From a practical point of view, if there are more than 20-30 items, the Column/Row will overflow anyway.
Caution ⚠️: Be careful when using the
MainAxisAlignment
property in aRow
orColumn
. You might spend hours debugging to figure out why the widgets are not aligned properly, only to realize in the end that it's because of the separators.
That’s it for now.
You can check the example on DartPad.
https://dartpad.dev/dccb5c9d81f2c8f8949be4b764181afd
Hey there, If you enjoyed this post then would you be able to do me a quick favour and share my latest blog post with your friends and colleagues? I'd really appreciate it and I think it could be valuable to them.
Thank you so much!
would love to see more examples for generators as well and a few use cases where it would make more sense
but...there is a Divider() widget