Animations are among the key factors that distinguish between the regular and outstanding user experience. UITableView provides us out-of-the box solution to animate list. In most of the cases this can be implemented very easy without any troubles and it will look very beautiful and professional, but sometimes, there is a situation where this is not the case.
In this blog post I will show basic implementation of this problem and give you some valuable advices to make your table view expand in some more elegant way. So without further ado let‘s get started.
Imagine you are working on a new feature. User story for this feature with acceptance criteria might look like this:
As a User I want to be able to see and edit my profile information.
- user information is divided into groups: personal (name, gender, nickname…), payout method (Aircash, PayPal, Visa…), notifications (email, push…)
- every group (section) needs to be expandable and collapsable
If you want to now how to solve this problem, check the next part of article.
Hang tight, things are going to become interesting!
Step by step explanation
So the first thing that comes to your mind when someone says section inside table view is of course header. Every section will have its own header at the top, and there will be three different types of sections inside our table view:
- Personal → holds the standard information about the user: username, email, password etc.
- Payout method → all different payment options user can use
- Notifications → section in which user is supposed to control upcoming notifications from different providers
1. Configuration of UITableView
Create EditProfileViewController and add tableView inside it. Pin all sides of tableView to view‘s edges. ViewControllers inside this project would not have any other UI elements because of simplicity and to keep focus on expanding and collapsing feature. You can find details about configuring table view inside EditProfileViewController class.
All registered cells are inside Cells folder and I would‘t explain how to make these. Focus will be on EditProfileHeaderView and handling of it inside EditProfileViewController. Enum EditProfileCellType is made for easier handling of all tableView cell‘s inside view controller. It accepts arguments that are view models of different cell types (personal, payMethod, notification). EditProfileHeaderViewModel is consisted of:
- titleText which corresponds to the desired title of a section
- cells which are children cells of each section
- variable isExpanded which gives information about section state
Data source for table view is moved inside EditProfileDataSource class to make code a bit cleaner and easier to follow. We assume that data fetched from server comes in nested format so our mocked data source has child data inside header data. Here is the code:
Everything to this point is pretty straightforward but now comes the fun part, magic of expanding and collapsing!
Expanding and collapsing should be done by clicking on header view of each section. Because of that simple tap gesture recognizer is added to view inside the class initializer. EditProfileHeaderViewDelegate notifies view controller that tap has happened and sends tapped header through toggleSection() function. Here you can see delegate implementation:
3. Expanding and collapsing 🧨
Let‘s start by looking at toggleSection() function on EditProfileViewController:
First thing that needs to be done is to find index of tapped header using indexOfHeader() method. Next step is to check if section is expanded or collapsed and according to that hide or show cells inside table view. Implementation of finding tapped header index and hiding and showing of cells is shown here:
After finding children index paths using findChildIndexPathsOfHeader() function we are ready to insert and delete that child cells. Deleting and inserting of UITableView rows is pretty easy and it‘s done with deleteRows() and insertRows() functions. “With” parameter inside both functions is in charge for animating deletion and insertion of cells. I encourage you to play around with it and find option that suits you the best. Run your program and you will be able to expand and collapse your table view cells for different section. Cool right, and it wasn‘t so hard?
Note: Insertion and deletion of cells could be done using reloadSection() function. Downside of this approach is that each time function is called it reloads all cells inside given section including the header.That causes strange behaviour of the arrow in the upper right corner when you try to animate it.
Downsides of this solution
Aldo you made a really nice looking feature inside your application there are some downsides of this implementation. Continue reading to find out how to fix them.🔨
Flickering when expanding and collapsing
- In some cases if you click multiple times on same header inside of table view, header will preform some type of strange looking jump. If you are perfectionist as I am, it is obvious that you want to fix this.
- Second strange thing that will occur is poor looking collapse animation. Maybe at this moment you don‘t see what am I talking about but when upgraded version comes to place, everything should be clearer. You now what they say: “You don‘t know how good a Ferrari really is, till the first time you drive it.”
In order to fix this problem, we will create EditProfileFixViewController. Main difference compared to EditProfileViewController will be implementation of section headers. At the new view controller, header will be implemented as UITableViewCell. Because of that dataSource will be converted to flatDataSource model for easier handling of data. Table view on the EditProfileFixViewController will have just one section.
As I said in the previous segment, header of EditProfileFixViewController will be implemented as UITableViewCell. For that reason EditProfileFixCellType looks like this:
Note: Don‘t forget to register EditProfileFixHeaderCell when configuring your table view, without doing so your application will crash
Data source for table view will be transformed from two-dimensional array to one-dimensional array. That is done by calling flatDataSource() function which will save flat data to flattenDataSource property of EditProfileFixDataSource. If you take some time and think about UI of table view, you will see that there is no reason to construct two-dimensional array at all. All cells inside of table view are just one list of elements and really they shouldn‘t be nothing more than that. So building dataSource for our table view at his way is far more elegant and sophisticated.
3. UITableViewDataSource functions
Data source functions are same as ones on the EditProfileViewController but with minor differences. Number of sections inside table view is set to 1 and there is one more case to handle when switching on flattenDataSource(header cell).
4. DidSelectRowAt function
With section header implemented as UITableViewCell we don‘t need to implement any delegates because we can react on tap with didSelectRowAt() function. Function implementation is done like this:
We can see that logic is same as the one for EditProfileViewController. After every click flattenDataSource is updated accordingly by calling flatDataSource() function. Hiding and showing cells is implemented with exact same functions as for the first example and would‘t be discussed one more time. So what we have done by making all these changes? Let‘s find out at results chapter.😎
- We can see that there is no flickering of header when exact same header is clicked multiple times. First problem solved.💪🏼
- Collapsing animation is much more smooth and there is now strange behavior at headers.🍾
Both view controllers are put inside tab bar so you can easily switch between of two and see the difference. I hope you can see that one on the right side is the way to go if you want smooth and good looking UI. On the next image you can see pros and cons of each implementation:
At the end of the story we can say that EditProfileFixViewController is far more elegant solution by terms of UI. By using this approach, your table view will look professional and easy to use. Flickers and UI bugs will be gone, and users wont’t be confused with some odd-looking animations. This may look like a small and unessential thing, but these things separate good apps from the best ones. Hope you learned something reading this article and if so, share it with your colleagues and let the knowledge spread.
Thank you and feel free to post questions and comments below.
You can find all project materials here:
Krešimir is a valuable member of our iOS team.
At Azikus, we design and develop top notch mobile and web apps.
We are a bunch of experienced developers and designers who like to share knowledge, always staying up to date with latest and newest technologies.
To find out more about what we do, feel free to check our website.