先来看一张效果图
需求分析
做一个商品分类展示,有三级列表,要求第一级列表能展开,显示二三级列表,同时就还能收起。每展开一级列表,要滚到顶部。(默认展开第一个一级列表)
实现
一级分类使用TableView
的viewForHeader
展示
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
FoldingSectionHeader *sectionHeaderView = [[FoldingSectionHeader alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, [self tableView:self heightForHeaderInSection:section]) withTag:section];
[sectionHeaderView setupWithBackgroundColor:[UIColor whiteColor]
titleString:[self titleForSection:section]
titleColor:[UIColor darkTextColor]
titleFont:[UIFont systemFontOfSize:14]
headerImage:[self imageForSection:section]];
sectionHeaderView.tapDelegate = self;
return sectionHeaderView;
}
同时实现viewForHeader
点击事件
#pragma mark - FoldingSectionHeaderDelegate
-(void)foldingSectionHeaderTappedAtIndex:(NSInteger)index
{
NSNumber *section = [NSNumber numberWithInteger:index];
if ([_multopenSectionArray containsObject:section]) {
NSArray *deleteArray = [self buildEditRowsWithSection:index];
[_multopenSectionArray removeObject:section];
[self deleteRowsAtIndexPaths:deleteArray withRowAnimation:UITableViewRowAnimationTop];
} else {
[[_multopenSectionArray copy] enumerateObjectsUsingBlock:^(NSNumber *obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray *otherDeleteArray = [self buildEditRowsWithSection:[obj integerValue]];
[_multopenSectionArray removeObject:obj];
[self deleteRowsAtIndexPaths:otherDeleteArray withRowAnimation:UITableViewRowAnimationTop];
}];
[_multopenSectionArray addObject:section];
NSArray *insertArray = [self buildEditRowsWithSection:index];
[self insertRowsAtIndexPaths:insertArray withRowAnimation:UITableViewRowAnimationTop];
if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(foldingTableView:scrollForHeaderInSection:)]) {
[_foldingDelegate foldingTableView:self scrollForHeaderInSection:index];
}
}
}
- 注意
deleteRowsAtIndexPaths
是UITableView
中移除表试图中具体某行的API,如果你对UITableView
的机制不是很了解的话,直接调用该函数很可能会导致XCode抛出异常。本人就遇到了。后来在断点跟踪这个API时发现,IOS在调用deleteRowsAtIndexPaths
之后又重新调用了tableView:numberOfRowsInSection
。要记住,在deleteRowsAtIndexPaths
之后要更新数据源。
三级列表一行需要展示多个数据,选择CollectionView
就比较合适了。所以,TableView
的每一个cell
上面放一个CollectionView
,二级分类展示在CollectionView
的UICollectionElementKindSectionHeader
上面
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if (kind == UICollectionElementKindSectionHeader) {
CategoryItemHeaderCell *cell = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:CategoryItemHeaderCellIdentifier forIndexPath:indexPath];
cell.headerTitle = self.model.name;
return cell;
}
return nil;
}
三级分类展示在CollectionView
的每一个item
上
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CategoryItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CategoryItemCellIdentifier forIndexPath:indexPath];
ThirdCateforyModel *thirdModel = self.model.array[indexPath.item];
cell.model = thirdModel;
return cell;
}
- 注意
在TableView
的自定义cell
里面要调用下面的方法,否则三级分类会不显示
- (void)layoutSubviews
{
[super layoutSubviews];
[itemCollectionView setFrame:CGRectMake(0, 0, kScreenWidth, self.frame.size.height)];
}