iOS - 二級連動(tableview包含 collectionview)
基本結構
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 了,需要的可以參考一下。
相關文章
- iOS自定義控制元件:自定義TableView、CollectionView空資料佔點陣圖iOS控制元件View
- 成品直播原始碼推薦,TableView/CollectionView 滑動頂部效果最佳化原始碼View
- iOS CollectionView 的那些事iOSView
- iOS tableView中的MVC、MVVMiOSViewMVCMVVM
- iOS面向切面的TableView-AOPTableViewiOSView
- iOS開發- tableView的協議iOSView協議
- IOS多型別Cell的tableView實現iOS多型型別View
- iOS tableView 分割線左右邊距調整iOSView
- iOS 產品新需求,要讓collectionView 的背景跟著Cell 一塊兒動!!!iOSView
- 【iOS】含tableView的ViewController基類的實現iOSViewController
- iOS模式分析 使用介面卡模式重構TableViewiOS模式View
- 『ios』view和tableview的截圖和圖片拼接iOSView
- CollectionView 單個選項卡的滑動View
- iOS初級開發學習筆記:一個頁面中自動計算cell的高度來自適應tableView的高度iOS筆記View
- WWDC 2018 :CollectionView 之旅View
- CollectionView 佈局收集View
- js二級聯動JS
- iOS開發之tableView左滑刪除的兩種方法iOSView
- iOS 動畫 - 窗景篇(二)iOS動畫
- 用列舉來驅動 TableView 開發View
- golang二級指標操作連結串列Golang指標
- Swift iOS : 如何一拖tableview到底的時候更新資料SwiftiOSView
- 一個CollectionView 選單View
- MVC的二級聯動MVC
- iOS 實現UINavigation全屏滑動返回(二)iOSUINavigation
- js 實現二級聯動JS
- iOS CoreData (二) 版本升級和資料庫遷移iOS資料庫
- 小資料二級聯動-封裝成一個二級聯動部分檢視封裝
- C++ Qt開發:TableView與TreeView元件聯動C++QTView元件
- 升級到iOS 18、降級回iOS 17iOS
- 如何優化tableView優化View
- TableView效能優化View優化
- iOS 圖示&啟動圖生成器(二)iOS
- Laravel+Vue 構建仿簡書二級評論系統包含郵件通知LaravelVue
- 原生JS實現二級聯動JS
- 系統學習iOS動畫之二:自動佈局iOS動畫
- TornadoFx的TableView元件使用View元件
- DVWA檔案包含全等級繞過方法