Our client came with a requirement of ‘meetings and to-do tasks’ application for iPad. Besides the basic to-do tasks functionality, this application had a complex UI requirement:
- The task list should be organized in a hierarchical nested list structure.
- It should also have expand/collapse functionality with smooth sliding animation.
- User should also be able to create new items at any position.
- User should sort items by moving an item from original position to any other position.
The Parent-Child list like functionality was already working in a web application. The HTML tags, <ul>, <li> provide an excellent Parent-Child relationship among visual components. With the help of jQuery plugins, it is a piece of cake to organize components in a nested list order.
Unfortunately, there was no such Parent-Child relationship available in Apple’s iOS SDK. The only component to draw a listing is UITableView but it doesn’t provide any nested list like structure.
- First of all we looked for some open sources for Tree like view implementation but due following limitation it couldn’t become a solution.Limitations: Unfortunately none of them was providing functionality like; re-ordering and creating new items at specific position.
- Another possibility was to create this structure from scratch using another component provided by Apple’s iOS SDK; i.e: UIView. The UIView component is similar to <div> element tag in HTML, but in addition the UIView component is capable of containing other child UIView components. Adding new child components is easy.Limitations: Idea of implementing above requirement from scratch was good in a sense that it was now possible to achieve our goal, but creating a list structure from scratch was time consuming when adjusting each UIView’s placement in vertical order. The UIView components are not automatically positioned when some other UIView components are added or deleted. In a vertical listing of 5 UIView components, if a new component is added at position 2, we have to make many updates in UI:
- Manually calculate the area of newly added item to place it at position 2 (adjusting width, height, x, y)
- Shift next components at position 3, 4, 5 to bottom (increase there y positions as much as the height of newly created item)
- Adjust overall page scrolling (so that if bottom components go out of screen they can accessed by scrolling)
- Same tedious calculation was needed when some item is deleted.
1- Maintaining Hierarchy:
After trying many possibilities, we finally decided not to re-invent the wheel. We used iOS built-in UITableView component which at least provides a single nested level list structure with automatic scroll handling. But this time instead of completely depending on this UI component, we created a data structure that keeps track of each Parent-Child relationship among data items. Some of its responsibilities provide the following information about data items:
- (MKTreeNode *)getNextSiblingForNode;
- (MKTreeNode *)getPreviousSiblingForNode;
- (MKTreeNode *)getFirstChildOfNode;
- (MKTreeNode *)getLastChildOfNode;
The data structure we created provides all information that we need to display an item and compute our custom logics on it. So now we are just using single nested level UITableView component. While displaying data items on the list, we check if it is a child item, we just indent all contents in it to the right with a fixed ‘x’ offset value, giving it a look of a child item.
2- Achieving Expand/Collapse functionality:
The second part of the requirement was the expand/collapse functionality, which again UITableView doesn’t provide. For this, we got the idea from some open sources. The basic idea was to remove the child data items with sliding animation in case of collapse. When need to expand it, we just add data items with sliding animation. This was also handled by our data structure:
- (void)addChild:(MKTreeNode *)newChild;
- (void)addChild:(MKTreeNode *)newChild atIndex:(NSUInteger)newIndex;
- (void)removeChild:(MKTreeNode *)child;
We managed a two dimensional temporary array, which was responsible for getting data from data structure and displaying it on screen. To maximize the adding/removing performance, we are doing remove/add operations on this two dimensional array.
3- Re-Order items/Sorting:
The requirement of re-ordering of items also becomes easy with our handy data structure. Just remove children from previous parent items, and add them in new parent. After that, re-draw the list using UITableView’s built-in method i.e.:
- [treeTableView reloadData];
By removing the default separator lines, we got a nested list like view: