Xamarin.Forms Expandable ListView
We all know Xamarin and in particular Xamarin.Forms is an excellent cross platform mobile application library which allows developers to create truly native apps from a single code-base. However, Xamarin.Forms generally only implements native features which are transferable between each of the major mobile platforms, so new developers moving to the platform can find it incredibly limiting.
For example, on my first Xamarin app one of the first things I needed was a CheckBox - I was so shocked to find there was not a CheckBox control I could just add to my page I nearly ditched Xamarin completely. I'm glad I managed to move past this because for many business apps the trade off between having all native features available and only having to make the app once is certainly worth it.
The lack of native features in Xamarin.Forms leads me to finding new and possibly strange, even hacky ways to get the functionality I want without writing platform specific code. Something I needed recently in one of my apps was an expandable ListView. Android has a good native implementation of this but Xamarin.Forms unsurprisingly does not.
I've made a demo app to explain how I created an expandable ListView using Xamain.Forms as you can see below it groups categories of food under expandable/collapsible headers, complete with terrible descriptions courtesy of Rachel Kelsey.
And this is how I achieved this using 100% shared code.
The list view is to be bound to a List of Lists, or more precisely an ObservableCollection of ObservableCollections. So that I can also add a search feature, I keep two copies of the list - one with all Foods and another containing only Foods which are expanded each time the Expand/Collapse button is clicked on a ListItem Header.
Firstly a simple class to store the details such as Name, Description and an icon Filename for each food item.
Next I made a FoodGroup class which is a subclass of ObservibleCollection<Food> and also implements IOnPropertyChanged so any changes to DataContext in code can be reflected in our list view. This means that when we create an instance of ObservibleCollection<FoodGroup>, we have a list of lists so The ListView contains a collection of FoodGroups and each FoodGroup contains a collection of Food.
The Expanded property keeps track on whether the group is expanded or collapsed. TitleWithItemCount just combines the number of Foods in the list with the title, this is so the user can see if a group has items when their parent group is collapsed. StateIcon will be an expanded icon when the list is expanded and collapsed when it's not. FoodCount is just needed to keep track of how many Foods are an Origional list.
Next i just added a static constructor so the list is populated with data at program start.
Next I created my ListView on the main page in XAML I added a few colours and formatting -just so it doesn't look completely terrible.
Notice I added a button to the GroupHeaderTemplate of the list, its icon binds to the StateIcon which returns a different icon file name if the group is Expanded or Collapsed.
Now for the code behind the view. Please note, it would be advisable to move this into a ViewModel and use a MVVM structure if you are making anything more than a demo app.
So I have two ObserviableCollection<FoodGroup>s one to contain all groups and items and other containing just the expanded ones. In the HeaderTapped event im just finding the index of the FoodGroup which has been tapped and then setting its Expanded property to the opposite. I then call UpdateListContent which will recreate _expandedGroups adding only foods which are Expanded.
Full solution is here.
There you have it, an expandable ListView in Xamain.Forms using 100% shared code. I'm very new to Xamarin and writing technical blogs so If you know of any ways I could improve this solution or have any questions please do not hesitate to leave me a comment.
In my next blog I will extend this solution to add a native search box at the top of the list.