基本结构
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 了,需要的可以参考一下。
网友评论