Implementation of IOS multilevel list

In the project development, the level list often encountered, the simple point of the two list by UITableView Header can be achieved, then the simple point of three list by Cell for adjusting the height can also achieve three list effect. But meeting a multi-level list, especially an unknown list of dynamic lists, is more troublesome.


A hierarchical list is similar to a tree structure, but not a two fork tree, but a multiway tree. Each node needs only two pointers to the parent and child nodes to form a tree. We will be in a multilevel list each object as a node, node has two attributes, respectively the parent node and child nodes ID.

Each tree has a virtual root node, its ID is rootID, all nodes in the parent node ID is rootID is the first level, corresponding to the tree structure in the depth (depth). In this way, each node object has parentID and childrenID, and childrenID is the ID of the node object.

We can check out the first level node through rootID, and then find the next level according to the node of the first level childrenID, and then, by analogy, determine the parent-child relationship of all nodes. At the same time, the leaf node and the first level node can also be determined, or
as the root node.

Design sketch

1. general multilevel list
Implementation of IOS multilevel list
general multilevel list.Gif
2. list the history of nodes
Implementation of IOS multilevel list
records node history status.Gif


1. according to the rootID to get all the first level nodes, and in the UITableView data source in dataSourceArr, display initialization list
2.: click the node cell, according to childrenID to find the next level nodes, and inserted into behind dataSourceArr currentNode,
3.: click the refresh display up to open the node cell, starting from dataSourceArr CurrentIndex1 if the node is less than level, currentNode level, node is removed, otherwise stop refresh the list. The
4. hits cell as the leaf node and does not respond to the unfolding or folding operation, and returns the node information.

DataSourceArr is one such order that conforms to the tree hierarchy:

Sequential.Png in Implementation of IOS multilevel list

Defining node objects

Implementation of IOS multilevel list
node object.Png


1. partial refresh problem

After each expansion or closure, refresh the list and start using

- - (void) reloadSections: (NSIndexSet *) sections, withRowAnimation: (UITableViewRowAnimation) animation

But it will lead to the overall flicker effect of the program and the experience is not good. Finally, partial refresh insertRowsAtIndexPaths and deleteRowsAtIndexPaths are considered. But
* Terminating app due to uncaught exception’NSInternalInconsistencyException’in reason:’attempt to refresh, delete row 2 from section 0 which only contains 2 rows before the update’

The reason for this is that current Cell is inconsistent with the numberOfRowsInSection when it refreshes, and when the insert or del cell is refreshed, the numberOfRowsInSection is inconsistent. Then try current, cell, and other cell, respectively, refresh, perfect refresh.

[_reloadArray removeAllObjects]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; if (currentNode.isExpand) {//expand [self expandNodesForParentID:currentNode.childrenID insertIndex:indexPath.row]; insertRowsAtIndexPaths:_reloadArray withRowAnimation:UITableViewRowAnimationNone]}else{[tableView //fold [self foldNodesForLevel:currentNode.level; currentIndex:indexPath.row] [tableView; deleteRowsAtIndexPaths:_reloadArray withRowAnimation: UITableViewRowAnimationNone];}

2. how to save node history

When the file level layer is relatively long, sometimes you want to turn off the hierarchy and then open it to keep the sub level open. We can give each node an extension property, when fold, only modify the currentNode attribute of expand, expand, the child node order isexpand = YES traversal, insert.

//expand - (NSUInteger) expandNodesForParentID: (NSString*) parentID insertIndex: (NSUInteger) insertIndex{for (int i = 0; i< _nodes.count; i++) {YKNodeModel *node = _nodes[i]; if ([node.parentID isEqualToString:parentID]) {if (self.isPreservation! = NO) {node.expand}; insertIndex++ [_tempNodes; insertObject:node atIndex:insertIndex] [_reloadArray; addObject:[NSIndexPath indexPathForRow:insertIndex inSection:0]]; //need reload nodes if (node.isExpand) {insertIndex = [self expandNodesForParentID:node.childrenID insertIndex:insertIndex];}}} return insertIndex;}

Demo address: