iOS - 二级连动(tableview包含 collectio

2018-09-03  本文已影响216人  CDLOG

基本结构

1,一级分类结构
一个 tableview列表
2,二级分类结构
一个 tableview 的每个 cell 都是一个 collectionview
根据一级分类选择的cell刷新二级分类 tableview
3,二级分类带索引
引用三方iOS列表的索引功能

模型结构

1,一级分类模型fModels
核心属性(一级分类包含二级分类的所有信息)

//记录一级分类是否选中,避免 cell 复用的 UI错误
@property (assign,nonatomic) BOOL select;
//带索引的二级品类信息
@property (nonatomic,strong) NSDictionary <NSString *,NSArray *>*sModelDicts;
//二级分类有序的索引数组,用于有序的加载二级分类 cell
@property (strong,nonatomic) NSArray * secondIndexKeyArr;
//二级分类序号对应的cell的高度,根据索引数组保存索引的高度信息 key:height
@property (strong,nonatomic) NSMutableDictionary* secondHeightDicts;

基本属性

@property (nonatomic,assign) NSInteger fID;
@property (nonatomic,strong) NSString * fName;

2,二级分类模型sModel
基本属性

@property (nonatomic,assign) NSInteger sID;
@property (nonatomic,strong) NSString * sName;
@property (assign,nonatomic) BOOL select;

加载一级分类和二级分类数据

通过网络加载数据,数据格式为

{
   Fmodel1的数据
  FModel1.SModel = {
                                "索引1" :[ 该索引下的全部二级分类 ]
                                "索引2" :[ 该索引下的全部二级分类 ]
                            }
 Fmodel2的数据
  FModel2.SModel = {
                                "索引1" :[ 该索引下的全部二级分类 ]
                                "索引2" :[ 该索引下的全部二级分类 ]
                            }
}

数据加载原理
1,一级分类数据
直接根据字典的方式加载
2,二级分类数据
·首先将二级分类索引排序,保存到secondIndexKeyArr 数组
·遍历每个索引下的二级分类对象数组保存到sModelDicts字典
·将该字典保存到一级分类对象属性sModelDicts
·将一级分类对象属性添加到一级分类数组
核心代码

//成功获取网络数据
if(success)
        {
//            保存一级分类对象的数组
            NSMutableArray * fModels = [NSMutableArray array];
//            遍历一级分类
            NSArray * cateArr = response[@"resultMap"][@"rows"];
            [cateArr enumerateObjectsUsingBlock:^(NSDictionary * obj, NSUInteger idx, BOOL * _Nonnull stop) {
//               一个一级分类对象
                FModel * model  = [[FModel alloc] init];
                model.fID       = [obj[@"firstProductCategoryCodeId"] integerValue];
                model.fName     = obj[@"firstProductCategoryName"];
//                获取一级分类下的全部索引和对应的二级分类
                NSDictionary * sDicts = obj[@"dataListCfs"];
                // 将索引排序
                NSArray *keys = sDicts.allKeys;
                keys = [keys sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
                    NSComparisonResult result = [obj1 compare:obj2];
                    return result == NSOrderedDescending;
                }];
//                保存有序的二级分类索引
                model.secondIndexKeyArr = [NSArray arrayWithArray:keys];
//                创建二级分类字典
                NSMutableDictionary * sModels = [NSMutableDictionary dictionary];
            
//                遍历索引取得每个索引下的二级品类数组 每个索引对应该索引下的二级分类数组对象
                [sDicts enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray* obj, BOOL * _Nonnull stop) {
//                 遍历将每个二级品类数组下的数组转二级品类对象数组
                    NSMutableArray *sobjArr = [NSMutableArray array];
                    [obj enumerateObjectsUsingBlock:^(NSDictionary* sobj, NSUInteger idx, BOOL * _Nonnull stop) {
                        sModel * models = [[sModel alloc] init];
                        models.sID      = [sobj[@"secondProductCategoryCodeIds"] integerValue];
                        models.sName    = sobj[@"secondProductCategoryName"];
                        [sobjArr addObject:models];
                    }];
                    
                    [sModels setObject:sobjArr forKey:key];
                }];
//                将二级分类字典保存到一级分类
                model.sModelDicts = [NSDictionary dictionaryWithDictionary:sModels];
                [fModels addObject:model];
                
            }];
            
        }

控制器

1,一级分类选中的复用问题
第一个 cell 默认选中
当点击 cell时,先将前一个 cell选中标志清除,再将当前 cell 选中,最后将当前 cell 赋值给选中cell属性
2,选中时刷新二级分类列表

//记录选中的一级分类,避免 cell 复用引起的 UI 问题
@property (strong,nonatomic) FirstCategoryCell * FirstCell;
//使用
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView == self.FirstCategoryTable) {
        FirstCategoryCell *cell = [self.FirstCategoryTable cellForRowAtIndexPath:indexPath];
        self.FirstCell.leftLine.hidden = YES;
        cell.leftLine.hidden = NO;
        self.selectCellRow = indexPath.row;
        self.FirstCell = cell;
        self.selectIndex = indexPath.row;
        [self reloadIndex];
    }else{
        
    }
}

下面代码的主要功能
1,根据选中的一级分类刷新二级分类
2,切换一级分类时索引重新回到最上方
3,相关的 tableView代理方法

//选中的二级分类序号
@property (assign,nonatomic) NSInteger  selectSection;
//选择一级分类的索引
@property (assign,nonatomic) NSInteger selectIndex;
@property (assign,nonatomic) NSInteger selectCellRow;
//选择的二级分类字典
@property (strong,nonatomic) NSDictionary * sModelDicts;


//根据选中的一级品类刷新二级品类
-(void)reloadIndex{

    //        根据key来存储每个cell的高度
    self.fModels[self.selectIndex].secondHeightDicts = [NSMutableDictionary dictionary];
    [self.fModels[self.selectIndex].secondIndexKeyArr enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSInteger count =  self.fModels[self.selectIndex].sModelDicts[obj].count;
        CGFloat height;
        if (count%self.rowItems>0) {
            height = (count/self.rowItems+1)*(self.itemHeight);
        }else{
            height = (count/self.rowItems)*(self.itemHeight);
        }
        [self.fModels[self.selectIndex].secondHeightDicts setObject:@(height) forKey:obj];
        
    }];
    //    刷新到顶部和序号刷新
    [self.SecondCategoryTable reloadData];
//
    [self.SecondCategoryTable scrollToRow:0 inSection:0 atScrollPosition:UITableViewScrollPositionTop animated:YES];
    self.selectSection = 0;
    //    索引列表
    self.sModelDicts = [NSDictionary dictionaryWithDictionary:self.fModels[self.selectIndex].sModelDicts];
    SCIndexViewConfiguration *indexViewConfiguration = [SCIndexViewConfiguration configuration];
    self.SecondCategoryTable.sc_indexViewDelegate = self;
    self.SecondCategoryTable.sc_indexViewConfiguration = indexViewConfiguration;
    self.SecondCategoryTable.sc_translucentForTableViewInNavigationBar = YES;
    self.SecondCategoryTable.sc_indexViewDataSource = self.fModels[self.selectIndex].secondIndexKeyArr;
}
#pragma mark 索引刷新


//每次重新选择一级品类刷新序号到顶部
- (NSUInteger)sectionOfTableViewDidScroll:(UITableView *)tableView{
    if (tableView == self.SecondCategoryTable) {
        return self.selectSection;
    }
    return 0;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    
    if ([scrollView isEqual: self.SecondCategoryTable]) {
        
        if (self.SecondCategoryTable.contentOffset.y > _oldY) {
            // 上滑
            _isUpScroll = YES;
        }
        else{
            // 下滑
            _isUpScroll = NO;
        }
        _isFirstLoad = NO;
    }
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    
    // 获取开始拖拽时tableview偏移量
    
    _oldY = self.SecondCategoryTable.contentOffset.y;
    
}

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section{
    
    if (tableView == self.SecondCategoryTable) {
        
        
        UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
        
        header.textLabel.textColor = color_custom(@"333333");
        
        header.contentView.backgroundColor = color_custom(@"FFFFFF");
        
        if(!_isUpScroll && (self.selectSection - section) == 1){
            
            //最上面组头(不一定是第一个组头,指最近刚被顶出去的组头)又被拉回来
            self.selectSection = section;

            
        }
    }
    
}


- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section{
    
    if(!_isFirstLoad && _isUpScroll){
        
        self.selectSection = section + 1;
        
        //最上面的组头被顶出去
        
    }
    
}
#pragma mark --tableViewDelegate
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (tableView == self.FirstCategoryTable) {
        return 1;
    }else{
        return self.fModels[self.selectIndex].sModelDicts.allKeys.count;
    }
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == self.FirstCategoryTable) {
        return self.fModels.count;
    }else{
//每个section都只有一个cell,里面是collection
        return  1;
    }
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView == self.FirstCategoryTable) {
        return 49;
    }else{
//        根据索引取出每个key对应的高度
        NSString *key = self.fModels[self.selectIndex].secondIndexKeyArr[indexPath.section];
        CGFloat height = [self.fModels[self.selectIndex].secondHeightDicts[key] doubleValue];
        return height;
        
    }
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (tableView == self.SecondCategoryTable) {
        return self.fModels[self.selectIndex].secondIndexKeyArr[section];
    }
    return nil;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView == self.FirstCategoryTable) {
        
        
        FirstCategoryCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstCategoryCellID];
        cell.leftLine.hidden = YES;
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        if (indexPath.row == self.selectCellRow) {
            cell.leftLine.hidden = NO;
        }
        [cell setUpModel:self.fModels[indexPath.row]];
        return cell;
    }else{
        SecondCategoryCell *cell = [tableView dequeueReusableCellWithIdentifier:SecondCategoryCellID];
        NSString *key =  self.fModels[self.selectIndex].secondIndexKeyArr[indexPath.section];
        [cell setupArrModel:self.fModels[self.selectIndex].sModelDicts[key]];
        return cell;
    }
    
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView == self.FirstCategoryTable) {
        FirstCategoryCell *cell = [self.FirstCategoryTable cellForRowAtIndexPath:indexPath];
        self.FirstCell.leftLine.hidden = YES;
        cell.leftLine.hidden = NO;
        self.selectCellRow = indexPath.row;
        self.FirstCell = cell;
        self.selectIndex = indexPath.row;
        [self reloadIndex];
    }else{
        
    }
}


二级分类的 Cell 包含collection相关方法

//加载数据。 注意要刷新 collectionview
-(void)setupArrModel:(NSArray <sModel *>*)model{
    self.smodelArr = model;
    [self.SecondCollectionView reloadData];
}

#pragma mark - collection delegate

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    NSLog(@"self.smodelArr.count = %ld",self.smodelArr.count);
    return self.smodelArr.count;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSTCollectionCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    
    sModel * smodel = [self.smodelArr objectAtIndex:indexPath.row];
//    sModel * smodel = [self.smodelArr ]
    [cell setUPsModel:smodel];
    [self.cellSet addObject:cell];
    if([self.delegate respondsToSelector:@selector(selectSModel)])
    {
        sModel * model = [self.delegate selectSModel];
        if([smodel isEqual:model])
        {
            SFModel * model = [[SFModel alloc] init];
            model.s_fModel = self.myModel;
            model.s_sModel = smodel;
            
            if([self.delegate respondsToSelector:@selector(cellDefaultModel:inCell:)])
            {
                [self.delegate cellDefaultModel:model inCell:cell];
            }
        }
        else
            [cell setToNormalAnimation:NO];
    }
    
    return cell;
}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSTCollectionCell * cell = (NSTCollectionCell *)[collectionView cellForItemAtIndexPath:indexPath];
    
    if([self.delegate respondsToSelector:@selector(canSelectModel:)])
    {
        if(self.single)
        {
            [self.cellSet enumerateObjectsUsingBlock:^(NSTCollectionCell * obj, BOOL * _Nonnull stop) {
                
                [obj setToNormalAnimation:YES];
                
            }];
        }
        SFModel * model = [[SFModel alloc] init];
        model.s_fModel = self.myModel;
        model.s_sModel = cell.mySModel;
        BOOL can = [self.delegate canSelectModel:model];
        if(can)
        {
            if([self.delegate respondsToSelector:@selector(selectModel:inCell:)])
            {
                [self.delegate selectModel:model inCell:cell];
            }
            else
                [cell selectModel];
        }
    }
    else
        [cell selectModel];
}

#pragma mark - UICollectionViewDelegateFlowLayout

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(self.frame.size.width/3 - 8, 60);
}

因为是在开发中写的代码,就不上 demo 了,需要的可以参考一下。

上一篇下一篇

猜你喜欢

热点阅读