From Android zero to kinda-middle is a new series, which explores stuff that I have learn in the last 2 years that elevates me from the worst Android developer in the world to āHe can be worseā. It will mostly focuses on the little things that donāt get talked about enough, and references to people who actually know what they are talking about.
I donāt have any statistics, but I think itās pretty safe to say that 95% of apps out there have RecyclerView somewhere in their app. And itās also pretty safe to say that in at least 80% of cases, there needs to be some kind of divider between items. Sometimes itās a gray/grey/grah line between items, but nowadays, itās quite often to just use a blank gap. And the easiest way to do that is just to add layout_margin to 1 side of the ViewHolder and call it a day. While it definitely works, itās not the most elegant solution, and thanks to the (sometimes ridiculously) flexibility of RecyclerView, there is an API that you can do some āpost processingā on each ViewHolder, and itās call ItemDecoration.
An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapterās data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.All ItemDecorations are drawn in the order they were added, before the item views (in onDraw() and after the items (in onDrawOver(Canvas, RecyclerView, RecyclerView.State).
This is from the official documentation, and itās pretty self-explanatory. And there are also couple of nice resources online that explains how to use it:
- This one goes much deeper on why the āeasyā way is not a good idea
- This StackOverflow Q&A tells you exactly how to implements it
And IMO, ItemDecoration really shines when it is being used with more complicated LayoutManager: Back in homify, one of the minor refactor task that I did was to stop having a ViewHolder to hold 3 ImageView together. Originally, we went the easy way, and create 1 ViewHolder that embed all the margins into the cell, and then the whole list can just use a LinearLayoutManager. But when it comes time to scale it up for tablet and orientation change, that just does not work well, and it adds a lot of boilerplate.
So the first thing that needs to change is to use GridLayoutManager instead, but then we have to figure out how to add the margin back in correctly. Without ItemDecoration, the 2 square ImageView translates to 2 ViewHolder: 1 with margin embedded on the right, the other one with margin embedded on the left. And because we support RTL languages such as Arabic + support down to API 17 back then, 2 more copies of each ViewHolder exists to add margin to the correct direction. Thatās pretty much the definition of boilerplate, and if we use that, at some point people are gonna forget the other configurations exists and break something.
And with ItemDecoration, what we need to do becomes much more logical: The 2 square uses the same ViewHolder, but the Adapter gives it 2 different viewType, so that ItemDecoration can pick that up, and add the margin in the correct direction. All the LTR & RTL logic is also encapsulated in the ItemDecoration itself (it just need Context. Itās not ideal, but IMO there are a lot of other stuff thatās worse in the code base anyway), so that we donāt have to stare at those verbose code everyday.
Again, if you have any questions, feedback, etc., leave a comment down below. Iād really appreciate it!
From Android zero to kinda-middle: divider/gap between RecyclerView.ViewHolders with ItemDecoration
How to add margins between ViewHolders in RecyclerView the right way.