UITableview 优雅的展开与收回
MaryannePor
8年前
<p>最近为项目的功能需求准备着,有一个很简单点击展开与收缩的功能需求,以前Swift中写过一个类似的功能,但是个人觉得不是特别好,当时就因为cell的复用导致了bug,并且这个需求是一直OC维护的项目,所以还是打算重写一个,现将项目中这个功能模块抽出来,与有相关需求的朋友分享一下。</p> <p>首先上一下效果图:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/bff00d137f5965587eb638c9dee2def8.gif"></p> <p>效果图</p> <p>1.首先说一下这个效果的思路:主要是通过维护一个模型来构建通过UITableviewCell 的列表</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/2dd11b8e3195031846882717d4564eef.png"></p> <p>可维护的模型</p> <p>本文主要的模型如上,并且这个模型可扩展性非常强,举个简单的例子的,DDSectionModel这个模型维护的是UITableViewHeaderFooterView,你可以将HeaderFooterView自定义为任何符合你需求的view;当然DDCellModel这个模型维护的是来维护cell,你可以定义cell来满足你的需求.</p> <p>在DDSectionModel这个模型中有一个加载数据源的方法,当然你可以将此方法单独定一个类或者定义一个协议去加载数据来降低耦合度,本文采用构建plist来当做数据源:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/afb4b68e620ff41bbb0b6824a3cef432.png"></p> <p>headerList.plist</p> <p>2.loadData:(void(^)(NSArray *models))finished 方法的实现,可根据个人需求来构建模型</p> <pre> <code class="language-objectivec">+ (void)loadData:(void(^)(NSArray *models))finished{ NSMutableArray *dataArr = [NSMutableArray array]; NSString *path = [[NSBundle mainBundle] pathForResource:@"headerList.plist" ofType:nil]; NSDictionary *diaryList = [NSDictionary dictionaryWithContentsOfFile:path]; NSArray *keyVal = diaryList.allKeys; NSArray *valueVal = diaryList.allValues; NSInteger keycount = keyVal.count; for (NSInteger i = 0; i< keycount ; i++) { DDSectionModel *sectionModel = [[DDSectionModel alloc] init]; sectionModel.isExpanded = NO; sectionModel.sectionTitle = keyVal[i]; NSMutableArray *cellArr = [NSMutableArray array]; NSInteger valuCount = ((NSArray *)valueVal[i]).count; for (NSInteger j = 0; j< valuCount; j++) { DDCellModel *cellModel = [[DDCellModel alloc] init]; cellModel.title = valueVal[i][j]; [cellArr addObject:cellModel]; } sectionModel.cellModels = cellArr; [dataArr addObject:sectionModel]; } finished(dataArr); }</code></pre> <p>3.接着我们自定义一下DDTableViewHeader</p> <pre> <code class="language-objectivec">//设置view的 subviews - (void)setupItems{ //右上角箭头图片 self.directionImageView.image = [UIImage imageNamed:@"brand_expand"]; self.directionImageView.frame = CGRectMake(ScreenW - 30, (44-8)/2, 15, 8); [self.contentView addSubview:self.directionImageView]; //btn覆盖header,相应点击 UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, ScreenW, 44)]; button.backgroundColor = [UIColor clearColor]; [self.contentView addSubview:button]; [button addTarget:self action:@selector(headerClick:) forControlEvents:UIControlEventTouchUpInside]; self.contentView.backgroundColor = [UIColor defaultColor]; self.contentView.layer.borderColor = [UIColor whiteColor].CGColor; self.contentView.layer.borderWidth = 0.5; } - (void)headerClick:(UIButton *)btn{ self.sectionModel.isExpanded = !self.sectionModel.isExpanded; [UIView animateWithDuration:0.25 animations:^{ if (!self.sectionModel.isExpanded) { self.directionImageView.transform = CGAffineTransformIdentity; }else{ self.directionImageView.transform = CGAffineTransformMakeRotation(M_PI); } }]; if (self.HeaderClickedBack) { self.HeaderClickedBack(self.sectionModel.isExpanded); } } - (void)setSectionModel:(DDSectionModel *)sectionModel{ _sectionModel = sectionModel; self.textLabel.text = sectionModel.sectionTitle; if (!_sectionModel.isExpanded) { self.directionImageView.transform = CGAffineTransformIdentity; }else{ self.directionImageView.transform = CGAffineTransformMakeRotation(M_PI); } }</code></pre> <p>4.剩下就负责构建UITableView了</p> <p>首先我们需要在ViewDidLoad中加载数据源,赋值给DataSoruce</p> <pre> <code class="language-objectivec"> [DDSectionModel loadData:^(NSArray *models) { self.dataSource = models; }];</code></pre> <p>实现相应的#pragma mark - Table view data source代理方法</p> <pre> <code class="language-objectivec">- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.dataSource.count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataSource[section].isExpanded ? (self.dataSource[section].cellModels.count) : 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MoreTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"myCellID"]; if (!cell) { cell = [[MoreTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"myCellID"]; } cell.cellModel = self.dataSource[indexPath.section].cellModels[indexPath.row]; return cell; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ DDTableViewHeader *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"header"]; if (!headerView) { headerView = [[DDTableViewHeader alloc] initWithReuseIdentifier:@"header"]; } headerView.sectionModel = self.dataSource[section]; headerView.HeaderClickedBack = ^(BOOL isExpand){ [tableView reloadSections:[[NSIndexSet alloc] initWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic]; }; return headerView; }</code></pre> <p>这样我们就能够优雅的实现了一个可点击展开与收回的UITableview,当然有人可能觉得,这样方式太依赖于模型,其实本文的耦合性已经很低了,Tableview列表的展示还需要依赖于数据源呢,只不过我们是构建了一个可维护的模型,可以随时扩展,当然大家有好的建议可以提出来,一起学习。</p> <p> </p> <p> </p> <p>来自:http://www.cocoachina.com/ios/20170418/19076.html</p> <p> </p>