? ? ? ?RATree是一個(gè)樹(shù)形視圖三方庫(kù)洞渤,可以在GitHub上下載,這個(gè)三方庫(kù)是通過(guò)對(duì)UITabelview
的封裝來(lái)實(shí)現(xiàn)了一個(gè)多層級(jí)醉蚁、無(wú)限制的自定義視圖拉背。你可以利用它來(lái)實(shí)現(xiàn)多種UI效果住闯,這里我實(shí)現(xiàn)了一個(gè)公司組織結(jié)構(gòu)增断箫、刪拂酣、改的功能。
? ? ? ?關(guān)于RATree的使用仲义,官方有一個(gè)英文的文檔說(shuō)明婶熬,看起來(lái)比較費(fèi)勁剑勾,我的小伙伴寫(xiě)了一篇文章基本上講明白了怎么個(gè)使用,有興趣的童鞋可以參考文章iOS樹(shù)狀視圖(折疊單元格)詳細(xì)使用
赵颅。
Demo思想
數(shù)據(jù)源
? ? ? ?RATree的數(shù)據(jù)源@property (strong,nonatomic) NSMutableArray *dataSource;
看起來(lái)可以和UITableView
的數(shù)據(jù)源一樣虽另,但是意義不同,數(shù)組中每個(gè)元素在UITableView
中一般指代每一行饺谬,而在RATree中指代的是幾個(gè)根節(jié)點(diǎn)捂刺,這個(gè)Demo中相當(dāng)于只有一個(gè)元素(Model),再來(lái)看一下Model的創(chuàng)建募寨。
#import <Foundation/Foundation.h>
@interface CellModel : NSObject
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSMutableArray *children;
- (id)initWithName:(NSString *)name children:(NSMutableArray *)array;
@end
? ? ? ?解釋一下name
就是這一行的標(biāo)題族展,你當(dāng)然也可以設(shè)置的更花哨,完全由你的界面決定拔鹰。但children
又是一個(gè)數(shù)組仪缸,就是子節(jié)點(diǎn)們,可以有很多列肢,也可以是空恰画。模型就是這樣創(chuàng)建的,這個(gè)Demo中一開(kāi)始初始化的時(shí)候瓷马,dataSource
中就一個(gè)CellModel
拴还,children
初始化了一下,但是沒(méi)有東西决采。添加子節(jié)點(diǎn)自沧,實(shí)際上就是對(duì)它的Model的children添加元素,元素的類(lèi)型還是CellModel
類(lèi)型树瞭。
代理方法
? ? ? ?數(shù)據(jù)源的問(wèn)題解決后拇厢,關(guān)鍵是怎么使用RATreeView的RATreeDelegate
和RATreeDataSource
。
#pragma mark- RATree的dataSouce
- (NSInteger)treeView:(RATreeView *)treeView numberOfChildrenOfItem:(nullable id)item
{
if (item == nil)
{
return self.dataSource.count;
}
CellModel *model = (CellModel *)item;
return model.children.count;
}
- (UITableViewCell *)treeView:(RATreeView *)treeView cellForItem:(nullable id)item
{
TreeTableViewCell *cell = [treeView dequeueReusableCellWithIdentifier:@"TreeTableViewCell"];
cell.delegate = self;
NSUInteger level = [treeView levelForCellForItem:item];
BOOL isExpand = [treeView isCellForItemExpanded:item];
[cell refreshCellWithItem:item andLevel:level andIsExpand:isExpand];
return cell;
}
- (id)treeView:(RATreeView *)treeView child:(NSInteger)index ofItem:(nullable id)item
{
if (item == nil) {
return self.dataSource[index];
}
CellModel *model = (CellModel *)item;
return model.children[index];
}
- (CGFloat)treeView:(RATreeView *)treeView heightForRowForItem:(id)item
{
return 50;
}
//將要展開(kāi)
- (void)treeView:(RATreeView *)treeView willExpandRowForItem:(id)item {
TreeTableViewCell *cell = (TreeTableViewCell *)[treeView cellForItem:item];
cell.imgView.image = [UIImage imageNamed:@"header_arrow_down"];
}
//將要收縮
- (void)treeView:(RATreeView *)treeView willCollapseRowForItem:(id)item {
TreeTableViewCell *cell = (TreeTableViewCell *)[treeView cellForItem:item];
cell.imgView.image = [UIImage imageNamed:@"header_arrow_right"];
}
- (void)treeView:(RATreeView *)treeView didSelectRowForItem:(id)item
{
[treeView deselectRowForItem:item animated:NO];
}
#pragma mark - TreeTableViewCell的delegate
-(void)clickTheBtn:(UIButton *)btn withTitle:(NSString *)name inTheCell:(TreeTableViewCell *)cell
{
if ([name isEqualToString:@"增加"]) {
[self addNodeToCell:cell];
}
else if([name isEqualToString:@"刪除"])
{
[self deleteNoteFromCell:cell];
}
else
{
[self editNoteToCell:cell];
}
}
? ? ? ?UITableView
的代理方法里晒喷,有倆個(gè)必須實(shí)現(xiàn)的方法孝偎,而在RATree里面有是三個(gè)。關(guān)鍵是這三個(gè)都什么意思凉敲,明白了就知道該怎么寫(xiě)了衣盾。按三個(gè)代理方法被調(diào)用的先后順序來(lái)說(shuō)明一下
-
- (NSInteger)treeView:(RATreeView *)treeView numberOfChildrenOfItem:(nullable id)item
? ? ? ?這個(gè)方法實(shí)際上它回調(diào)回來(lái)給你的參數(shù)有treeView
和item
,treeView
沒(méi)什么好說(shuō)的爷抓,告訴你是哪個(gè)treeView势决,item
其實(shí)返回的是你當(dāng)前視圖這一行(不論父節(jié)點(diǎn)還是子節(jié)點(diǎn))的父親節(jié)點(diǎn)對(duì)象。當(dāng)最開(kāi)始的根節(jié)點(diǎn)的時(shí)候蓝撇,item返回的是nil果复,其他情況下就會(huì)返回父節(jié)點(diǎn)對(duì)象。然后代理方法問(wèn)你要這個(gè)item
孩子們有幾個(gè)渤昌?你告訴它就是了虽抄,return出去走搁。 -
- (id)treeView:(RATreeView *)treeView child:(NSInteger)index ofItem:(nullable id)item
? ? ? ?這個(gè)方法緊接著被調(diào)用,簡(jiǎn)單的來(lái)說(shuō)他給你的參數(shù)item
還是當(dāng)前視圖這一行的父節(jié)點(diǎn)Model迈窟,如果是空私植,就代表當(dāng)前視圖是根節(jié)點(diǎn)。index
實(shí)際上是告訴你這一次的回調(diào)是第幾個(gè)孩子的回調(diào)车酣。說(shuō)白了就是它告訴你哪個(gè)treeView下哪個(gè)節(jié)點(diǎn)(item)的第幾個(gè)(index)孩子曲稼,是個(gè)什么對(duì)象(model)?你return這個(gè)對(duì)象(model)就行了骇径。 -
- (UITableViewCell *)treeView:(RATreeView *)treeView cellForItem:(nullable id)item
? ? ? ?這方法一看就是到它是問(wèn)你要Cell
呢躯肌,告訴你哪個(gè)treeView
,哪個(gè)模型Model(其實(shí)也全靠第2個(gè)代理方法你return的者春,它才知道)破衔,然后問(wèn)你要Cell
。這里實(shí)際上和UITableView
不同钱烟,更直接的告訴你Model了晰筛,咱們以前都是self.dataSouce[indexPath.row]
來(lái)找到模型,這個(gè)封裝的直接告訴你模型了(item)很爽吧拴袭。
總結(jié)
? ? ? ?其他的代理方法和自身的方法不說(shuō)了自己研究吧读第,都可以看名字猜意思。至于增刪改的思路就是拥刻,點(diǎn)擊cell
的事件全部回調(diào)到controller
去執(zhí)行怜瞒,然后順便把自己(也就是self)當(dāng)參數(shù)回調(diào)出去,然后般哼。然后通過(guò)數(shù)據(jù)源找到對(duì)應(yīng)的模型吴汪,修改就是了,然后刷新蒸眠。思路就是漾橙,視圖永遠(yuǎn)跟著模型走,要改什么不要去改界面楞卡,去改模型霜运,然后刷頁(yè)面,這樣就不會(huì)錯(cuò)了蒋腮,尤其是在這種復(fù)用的機(jī)制下淘捡。我覺(jué)得這個(gè)三方庫(kù)一開(kāi)始看我也很頭疼,和小伙伴研究了一下總算理清楚思路了池摧,只要把數(shù)據(jù)源和三個(gè)代理方法掌握了焦除,就一切OK了。