iOS多級列表實現(xiàn)代碼
在項目開發(fā)中,層級列表經(jīng)常遇到,簡單點的二級列表利用UITableView的Header就可以實現(xiàn),再簡單點的三級列表通過對Cell高度進行調整也可以實現(xiàn)三級列表的效果。但遇到多級列表,尤其是層次不明的動態(tài)列表就比較麻煩了。
原理
層級列表和樹形結構比較類似,不過不是二叉樹,而是多叉樹。每個節(jié)點只需要擁有指向父節(jié)點和子節(jié)點的兩個指針,就能形成一顆樹。我們將多級列表中每一級對象看作一個node,node擁有兩個屬性,分別為父節(jié)點和子節(jié)點的ID。
每棵樹有個一個虛擬的root節(jié)點,它的ID為rootID,所有節(jié)點中凡是父節(jié)點ID為rootID的便是第一級,對應樹結構中的depth(深度)。這樣每一個node對象就都擁有了parentID和childrenID, childrenID為node對象的ID。
我們可以通過rootID查出第一級node,再根據(jù)第一級node的childrenID查出下一級,依次類推,確定所有節(jié)點的父子關系。同時也可以確定葉子節(jié)點和第一級節(jié)點,也可稱
為根節(jié)點。
效果圖
1.一般多級列表

2.記錄節(jié)點歷史狀態(tài)的列表

思路
1.首先根據(jù) rootID 獲取所有第一級節(jié)點,并放入UITableView的數(shù)據(jù)源 dataSourceArr 中,展示初始化列表
2. 展開: 點擊節(jié)點cell,根據(jù) childrenID 查找下一級nodes,并插入到 dataSourceArr 中currentNode的后面,刷新展示
3. 收攏: 點擊以打開節(jié)點cell,從 dataSourceArr 的CurrentIndex+1開始,如果該節(jié)點的level小于currentNode的level,則移除node,否則停止刷新列表。
4.點擊cell為葉子節(jié)點則不響應展開或收攏操作,并把節(jié)點信息通過返回。
dataSourceArr中是這樣的一種符合樹層級結構的順序:

定義節(jié)點對象

遇到問題
1.局部刷新的問題
每次展開或收攏以后刷新列表,一開始采用
但會導致節(jié)目有整體閃爍的效果,體驗不好。最后考慮采用局部刷新 insertRowsAtIndexPaths 和 deleteRowsAtIndexPaths 。
但在刷新中會報錯
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 2 from section 0 which only contains 2 rows before the update'
推測原因是 current Cell在刷新時的numberOfRowsInSection和刷新insert or del的cell時numberOfRowsInSection不一致導致 。然后嘗試current cell和其他cell分別刷新,完美刷新。
[_reloadArray removeAllObjects];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
if (currentNode.isExpand) {
//expand
[self expandNodesForParentID:currentNode.childrenID insertIndex:indexPath.row];
[tableView insertRowsAtIndexPaths:_reloadArray withRowAnimation:UITableViewRowAnimationNone];
}else{
//fold
[self foldNodesForLevel:currentNode.level currentIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:_reloadArray withRowAnimation:UITableViewRowAnimationNone];
}
2.怎么保存節(jié)點歷史狀態(tài)
當文件級層比較多時,有時希望能關掉層級后再打開時還能保留子層級的打開狀態(tài)。我們可以會給每一個node一個是否展開的屬性,當fold時只修改currentNode的expand屬性,expand時對子節(jié)點序isexpand=YES的進行遍歷插入。
//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) {
node.expand = NO;
}
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地址:
https://github.com/YangKa/YKMutableLevelTableView.git
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
iOS開發(fā)中UITabBarController的使用示例
這篇文章主要介紹了iOS開發(fā)中UITabBarController的使用示例,代碼基于Objective-C進行演示,需要的朋友可以參考下2015-09-09
iOS UITextView 首行縮進 撤銷輸入 反撤銷輸入的實現(xiàn)代碼
本文是腳本之家小編給大家分享的iOS UITextView 首行縮進 撤銷輸入 反撤銷輸入的實現(xiàn)代碼,需要的朋友參考下吧2017-09-09

