本文實例為大家分享了bleView多層展開與收起的具體代碼,供大家參考,具體內容如下
規則要求:
想法:
數據存儲
//每個目錄的數據結構如下:@interface OpenTest : NSObject@property (copy, nonatomic) NSString *title; //非首層展示的標題@property (assign, nonatomic) NSInteger level; //決定偏移量大小@property (copy, nonatomic) NSString *openUrl; //最后一層跳轉的規則@property (copy, nonatomic) NSMutableArray *detailArray; //下一層的數據@property (assign, nonatomic) BOOL isOpen; //是否要展開@property (copy, nonatomic) NSString *imageName; //首層的圖片@end
其中,因為detailArray中存儲的對象也應該是OpenTest, 所以需要在OpenTest.m中借助MJExtension (在github上下載并加入到項目中)進行顯式轉化。
#import "OpenTest.h"@implementation OpenTest- (instancetype)init { self = [super init]; if (self) { [OpenTest mj_setupObjectClassInArray:^NSDictionary *{ return @{ @"detailArray" : [OpenTest class] }; }]; } return self;}@end
數據處理
開始建造源數據dataArray,該數組可明確層級關系,并且得到展示數組_resultArray。建造過程如下:
- (void)initData {_dataArray = [NSMutableArray new];_resultArray = [NSMutableArray new];NSMutableArray *secondArray1 = [NSMutableArray new];NSMutableArray *threeArray1 = [NSMutableArray new];NSMutableArray *fourArray1 = [NSMutableArray new];NSArray *FirstTitleArray = @[@"FirstTitle1", @"FirstTitle2", @"FirstTitle3", @"FirstTitle4", @"FirstTitle5", @"FirstTitle6", @"FirstTitle7", @"FirstTitle8", @"FirstTitle9", @"FirstTitle10"];NSArray *SecondTitleArray = @[@"SecondTitle1", @"SecondTitle2", @"SecondTitle3"];NSArray *ThreeTitleArray = @[@"ThreeTitle1", @"ThreeTitle2", @"ThreeTitle3", @"ThreeTitle4"];NSArray *FourTitleArray = @[@"FourTitle1", @"FourTitle2", @"FourTitle3"];NSArray *imageArray = @[@"scroller1", @"scroller2", @"scroller3", @"scroller4", @"scroller5", @"scroller6", @"scroller7", @"scroller8", @"scroller9", @"scroller10"];//第四層數據for (int i = 0; i < FourTitleArray.count; i++) { OpenTest *model = [[OpenTest alloc] init]; model.title = FourTitleArray[i]; model.level = 3; model.isOpen = NO; [fourArray1 addObject:model];}//第三層數據for (int i = 0; i < ThreeTitleArray.count; i++) { OpenTest *model = [[OpenTest alloc] init]; model.title = ThreeTitleArray[i]; model.level = 2; model.isOpen = NO; model.detailArray = fourArray1; [threeArray1 addObject:model];}//第二層數據for (int i = 0; i < SecondTitleArray.count; i++) { OpenTest *model = [[OpenTest alloc] init]; model.title = SecondTitleArray[i]; model.level = 1; model.isOpen = NO; model.detailArray = [threeArray1 mutableCopy]; [secondArray1 addObject:model];}//第一層數據for (int i = 0; i < FirstTitleArray.count; i++) { OpenTest *model = [[OpenTest alloc] init]; model.title = FirstTitleArray[i]; model.level = 0; model.isOpen = NO; model.detailArray = [secondArray1 mutableCopy]; model.imageName = imageArray[i]; [_dataArray addObject:model];}//處理源數據,獲得展示數組_resultArray[self dealWithDataArray:_dataArray];}/** 將源數據數組處理成要展示的一維數組,最開始是展示首層的所有的數據 @param dataArray 源數據數組 */- (void)dealWithDataArray:(NSMutableArray *)dataArray {for (OpenTest *model in dataArray) { [_resultArray addObject:model]; if (model.isOpen && model.detailArray.count > 0) { [self dealWithDataArray:model.detailArray]; }}}
當首層沒有展開數據時,點擊首層展開第二層數據,比較容易實現,即在_resultArray添加下一層數據。添加數據方法如下:
/** 在指定位置插入要展示的數據 @param dataArray 數據數組 @param row 需要插入的數組下標 */- (void)addObjectWithDataArray:(NSMutableArray *)dataArray row:(NSInteger)row {for (int i = 0; i < dataArray.count; i++) { OpenTest *model = dataArray[i]; model.isOpen = NO; [_resultArray insertObject:model atIndex:row]; row += 1;}}
收起方法實現如下:
/** 刪除要收起的數據 @param dataArray 數據 @param count 統計刪除數據的個數 @return 刪除數據的個數 */- (CGFloat)deleteObjectWithDataArray:(NSMutableArray *)dataArray count:(NSInteger)count {for (OpenTest *model in dataArray) { count += 1; if (model.isOpen && model.detailArray.count > 0) { count = [self deleteObjectWithDataArray:model.detailArray count:count]; } model.isOpen = NO; [_resultArray removeObject:model];}return count;}
在已經展開的時候點擊另外一個目錄,要先收起再展開。因為每個層次只有一個目錄是展開的,所以收起的時候,只需要跟同層次的目錄數據比較,如果是已經打開的,則刪除打開目錄的所有子層。方法如下:
/** 與點擊同一層的數據比較,然后刪除要收起的數據和插入要展開的數據 @param model 點擊的cell對應的model @param row 點擊的在tableview的indexPath.row,也對應_resultArray的下標 */- (void)compareSameLevelWithModel:(OpenTest *)model row:(NSInteger)row {NSInteger count = 0;NSInteger index = 0; //需要收起的起始位置//如果直接用_resultArray,在for循環為完成之前,_resultArray會發生改變,使程序崩潰。NSMutableArray *copyArray = [_resultArray mutableCopy];for (int i = 0; i < copyArray.count; i++) { OpenTest *openModel = copyArray[i]; if (openModel.level == model.level) { //同一個層次的比較 if (openModel.isOpen) { //刪除openModel所有的下一層 count = [self deleteObjectWithDataArray:openModel.detailArray count:count]; index = i; openModel.isOpen = NO; break; } }}//插入的位置在刪除的位置的后面,則需要減去刪除的數量。if (row > index && row > count) { row -= count;}[self addObjectWithDataArray:model.detailArray row:row + 1];}
界面
系統的tableviewcell 無法修改textLabel的位置,需要修改偏移量有兩種方法。
1、繼承UITableViewCell, 然后重寫父類的方法 - layoutSubviews, 在該方法中修改textLabel的frame。
2、在cell.contentView 中添加一個label。
我這里使用的是第二種方法:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; cell.selectionStyle = UITableViewCellSelectionStyleNone; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(15, 0, UI_SCREEN_WIDTH / 2, 32)]; label.font = [UIFont systemFontOfSize:14]; label.tag = LabelTag; [cell.contentView addSubview:label]; } for (UIView *view in cell.contentView.subviews) { if (view.tag == LabelTag) { ((UILabel *)view).text = model.title; ((UILabel *)view).frame = CGRectMake(15 + (model.level - 1) * SpaceWidth , 0, UI_SCREEN_WIDTH / 2, 32); } }
最后在didSelectRowAtIndexPath方法中實現點擊展開與收起,方法如下:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {NSInteger row = indexPath.row;OpenTest *model = _resultArray[row];if (model.isOpen) { //原來是展開的,現在要收起,則刪除model.detailArray存儲的數據 [self deleteObjectWithDataArray:model.detailArray count:0];}else { if (model.detailArray.count > 0) { //原來是收起的,現在要展開,則需要將同層次展開的收起,然后再展開 [self compareSameLevelWithModel:model row:row]; } else { //點擊的是最后一層數據,跳轉到別的界面 NSLog(@"最后一層"); }}model.isOpen = !model.isOpen;//滑動到屏幕頂部for (int i = 0; i < _resultArray.count; i++) { OpenTest *openModel = _resultArray[i]; if (openModel.isOpen && openModel.level == 0) { //將點擊的cell滑動到屏幕頂部 NSIndexPath *selectedPath = [NSIndexPath indexPathForRow:i inSection:0]; [tableView scrollToRowAtIndexPath:selectedPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; }}[tableView reloadData];}
效果
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答