Android Accordion Layout or: How I Learned to Stop Copying and Love the Reusable Components
I understand some of you are here to only check out the code and copy it in their project. I’ve been there. However, I recommend reading this article thoroughly, not just because I wrote it, but because I believe it might be helpful, especially for people who are relatively new to Android and Object-Oriented Programming in general. For those of you who’d like to skip to the code, here you go.
If you ever worked on an Android (or any other, for that sake) application, you probably reached a point where you needed a custom layout. No matter if it is a simple, or a complex layout, you need to do something that’s not offered by your framework. And you have two options:
- Search the Internet hoping somebody already did that
- Write the code yourself
Everyone loves option number one. And why not, right? It’s easy. Just get the open-source code/library somebody wrote and use it in your project. Simple as that. But sometimes you realize you need something nobody did (and published online). Then, you have only one option remaining. Option #2. Where to get started?
First of all, think about reusability. In my early days as a software engineer, I did not think about it too often. I needed something — I wrote the code for it and it worked. Great! Or, is it? If you think you will ever need that component once, yes, sure. But, if you think that, chances are, you are wrong.
The AccordionLayout that we are going to cover in this article is just a small part of components I thought I won’t ever need again, but in the end, I did. I needed a custom view, so I implemented (a tightly coupled) code that fulfilled the purpose. But this code was for one-time use only — it was not reusable. And the next time I needed a similar component, I started implementing it again. Halfway through the job, I realized, I’ve already done (something) like this! So I went back, copied that same code and tried to use it in the new project where I needed it. But it was tightly coupled with the rest of the code and required a lot of work to be adjusted. This was not a reusable component, but rather a useless one…
Fast forward a couple of years… I needed a custom view, I did what most of you would do. I Googled ‘accordion layout android’. There were a few results (kudos to the authors), but they were not what I was looking for. So, I decided I needed to implement a custom component. Only, this time, I was going to make it reusable, so I (and others) can use it wherever it’s needed.
And this is where the boring part ends. Let’s get to the code and explain it a bit. Actually, there is not much explaining to do. First of all, it’s written in Kotlin, like all new components should be, in my opinion. But no worries, if you are using Java, they are totally compatible.
The main class, AccordionLayout, is a child of LinearLayout and it’s simple as it gets:
The AccordionLayout works with ExpandableViews only. What are they? Just another simple class that defines the general behavior of an Accordion layout:
Every view that inherits from the ExpandableView abstract class should implement a few methods that match the accordion behavior and that’s all, the rest is handled within the abstract class. The abstract functions:
abstract fun getExpandableViewId(): Int
abstract fun getRootViewId() : Int
abstract fun getClickableViewId() : Int
abstract fun getLayoutResId(): Int
require the ids of a few layouts that should be a part of an expandable view, that is:
- Expandable View — the view that should be expanded/closed on click
- Root View — the parent view in the expandable layout
- Clickable View — the view that can be clicked and will trigger the expansion/closing of other views
- Layout Resource — the id of the layout resource of the custom accordion layout file
A few default layouts are at your disposal, too, so you don’t waste time at creating generic layouts for the accordion. This is how they look in a sample activity using the different layouts:
TitleAccordionElement
DescriptionAccordionElement
ImageAccordionElement
This implementation allows using different layouts within the AccordionLayout if needed, it only requires that all of those layouts extend the ExpandableView abstract class. I have also implemented a Builder to facilitate the creation and customization of such views. The Builder accepts several arguments and based on the provided arguments it generates the appropriate view for you.
This is a sample layout generated by the AccordionElementBuilder:
And the resulting layout:
Finally, initializing the AccordionLayout with views is really easy. This gist uses all of the sample views as an example:
And the result looks something like this. You can see the functionality and the different layouts.
This example is just to showcase the basic accordion functionality and the different layouts (I know it doesn’t look too good). But, that’s the thing, you can customize it any way you want and use it, or you can create your own layout. Here’s how a sample layout looks like:
All you need to do in order to make the view extendable is provide the different layout resources that were described earlier. If you want to add custom animation for expanding and collapsing, you can do so by overriding the expand() and collapse() methods, as shown in the previous sample.
As you can see, this component is now customizable and reusable and you can use it for your convenience if you ever need it. But in general, any component can be reusable, you just need to plan for it. Use the SOLID principles, keep your code as loosely coupled as possible. Even if you don’t think you’ll ever need to use a component again, somebody else might. And as someone who has used his fair share of open-source libraries, I think it’s nice to help others. The open source community gives us, the developers, a lot. We need to give back to the community. This is my humble attempt to provide an open source library that anyone can use. If you think something can be improved, you are welcome to open a PR or comment.
You can find the source code on my Git account, as well as the built & ready-to-use AAR file.