概述
項目中要實現(xiàn)一個樓盤表,要求實現(xiàn)以下功能:
1、支持無數(shù)據(jù)的地方進(jìn)行補(bǔ)位;
2、支持行列任意拓展;
3、支持支持多向聯(lián)動;
4、支持上下表格合并。
后面經(jīng)過研究,考慮通過UICollectionView的靈活嵌套的方式來進(jìn)行實現(xiàn)。先看下最后實現(xiàn)效果:


功能實現(xiàn)
一個表格制作完總結(jié)起來主要就是三個要點(diǎn):
- 視圖布局
- 聯(lián)動實現(xiàn)
- 數(shù)據(jù)構(gòu)造
1、視圖布局
由于需求要求要實現(xiàn)行列任意拓展,首先就想到UICollectionView的復(fù)用特性,有了復(fù)用再多的數(shù)據(jù)頁面滑起來也會流程一些,還有就是需求要求上下表格支持合并,然后就可以利用UICollectionView設(shè)置item高度的方式來進(jìn)行實現(xiàn)。但是一般手機(jī)屏幕一般不會大到把橫向或者豎向的表格都能展示出來,所以就得要求樓盤表既能橫向滑動又能豎向滑動。為了實現(xiàn)這個要求單個UICollectionView肯定也是實現(xiàn)不了要求了,單個UICollectionView只能基本實現(xiàn)橫向或者豎向的滑動并復(fù)用了,所以這時候想到的是UICollectionView雙層嵌套,UICollectionView中的UICollectionViewCell套UICollectionView,大的一個負(fù)責(zé)橫向滑動,嵌套的負(fù)責(zé)豎向滑動?;静季志褪沁@樣子了,可以看到整個頁面基本上都是用UICollectionView來進(jìn)行實現(xiàn)的。

如果想控制表格合并與否,合并哪些,這些就是根據(jù)數(shù)據(jù)源傳值過來的數(shù)據(jù)來進(jìn)行基本控制了,我們定義的規(guī)則是當(dāng)highNominalLayer大于lowerNominalLayer時就進(jìn)行表格合并,和并數(shù)量就是highNominalLayer與lowerNominalLayer差值加一,當(dāng)然進(jìn)行表格合并表格時還要注意把中間的間距加上,不然會出現(xiàn)對不齊的情況了。
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (self.itemArr.count > indexPath.row) {
//處理表格合并
ZHItemModel *infoModel = self.itemArr[indexPath.row];
NSInteger difference = infoModel.highNominalLayer - infoModel.lowerNominalLayer + 1;
CGFloat height = KITEMHEIGHT * difference + KSPACE * (difference - 1);
return CGSizeMake(KITEMWIDTH, height);
}
return CGSizeMake(KITEMWIDTH, KITEMHEIGHT);
}
2、聯(lián)動實現(xiàn)
我們知道iOS中滑動的結(jié)果顯現(xiàn)就是列表contentOffset偏移量值的改變,所以要實現(xiàn)聯(lián)動的基本原理也就很簡單了,只要滑動一個控件時把當(dāng)前控件的contentOffset偏移量賦值給想要聯(lián)動控件的contentOffset就OK了。這樣兩個控件的contentOffset偏移量始終一致,動與停也就會一致了,聯(lián)動也就基本實現(xiàn)了。兩個單獨(dú)的控件這樣賦值可以很快實現(xiàn),但是由于表格中用了UICollectionView的嵌套,滑動的時候會出現(xiàn)復(fù)用的情況,所以如果想要簡單的賦值估計會出現(xiàn)無從賦值的情況,怎么去解決這個賦值的問題呢,我的處理方式是循環(huán)遍歷取出再賦值。
/** 處理多向滑動 */
- (void)itemCollectionViewDidScroll:(UIScrollView *)scrollView
{
[self scrollViewDidScroll:scrollView];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == self.headCollectionView){
self.bgCollectionView.contentOffset = CGPointMake(self.headCollectionView.contentOffset.x, 0);
}else if (scrollView == self.bgCollectionView){
self.headCollectionView.contentOffset = CGPointMake(self.bgCollectionView.contentOffset.x, 0);
}
if (scrollView == self.headCollectionView || scrollView == self.bgCollectionView || scrollView == self.leftCollectionView){
[self updateCollectionViewOffictYWithView:self.leftCollectionView];
}else{
self.leftCollectionView.contentOffset = CGPointMake(0, scrollView.contentOffset.y);
[self updateCollectionViewOffictYWithView:self.leftCollectionView];
}
}
//循環(huán)取出賦值偏移量
- (void)updateCollectionViewOffictYWithView:(UIScrollView *)view
{
NSIndexPath *indexPath = [self.bgCollectionView indexPathForItemAtPoint:self.bgCollectionView.contentOffset];
NSInteger min = indexPath.section - self.refreshCount;
NSInteger max = indexPath.section + self.refreshCount;
max = max > self.dataArr.count ? self.dataArr.count : max;
min = min > 0 ? min : 0;
for (NSInteger i = min; i < max; i ++) {
for (NSInteger j = 0; j < [self.dataArr[i] count]; j ++) {
ZHBgCollectionViewCell *cell = (ZHBgCollectionViewCell *)[self.bgCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];
if (!cell) {
continue;
}
if (cell.collectionView.contentOffset.y == view.contentOffset.y) {
continue;
}
cell.collectionView.contentOffset = CGPointMake(0, view.contentOffset.y);
}
}
}
通過屆定一個范圍,通過滑動時調(diào)用cellForItemAtIndexPath方法取出collectionView再賦值contentOffset這樣的方式來解決無法賦值的情況,以此來解決因為嵌套聯(lián)動的問題。
3、數(shù)據(jù)構(gòu)造
由于我們收到后臺返回的數(shù)據(jù)是一維數(shù)組,并且是只返回有值的數(shù)據(jù),空白表格是不返回數(shù)據(jù)的。但是由于制作的表格是用的嵌套的方式來實現(xiàn)的界面,所以需要根據(jù)后臺返回數(shù)據(jù)來進(jìn)行一下本地處理,轉(zhuǎn)換成三維數(shù)組,而且空白表格也不返回數(shù)據(jù),所以本地也要處理一下空白數(shù)據(jù)占位填充。為了更快捷的去數(shù)據(jù)處理,在這里推薦一個為Objective-C帶來Linq風(fēng)格的流暢查詢的庫LinqToObjectiveC?;咎幚磉壿嬍峭ㄟ^NSSortDescriptor類按單元、單元內(nèi)序號、樓層進(jìn)行一次整體排序,排序好后進(jìn)行分組切割,空值補(bǔ)位,去重,然后進(jìn)行值的保存,最后實現(xiàn)了數(shù)據(jù)的構(gòu)造。
/** 處理數(shù)據(jù)并進(jìn)行傳值 */
- (void)getQueryWithLayersCount:(NSInteger)layersCount topLayers:(NSInteger)topLayers
{
NSMutableArray *dataArr = [NSMutableArray array];
NSString *strPath = [[NSBundle mainBundle] pathForResource:@"layer" ofType:@"geojson"];
NSString *layerJson = [[NSString alloc] initWithContentsOfFile:strPath encoding:NSUTF8StringEncoding error:nil];
NSMutableArray *jsonArr = [ZHItemModel mj_objectArrayWithKeyValuesArray:layerJson];
ZHItemModel *layerModel = [[ZHItemModel alloc] init];
//總樓層
layerModel.layersCount = layersCount;
layerModel.topLayers = topLayers;
//key :按照unitNum屬性 升序排序
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"unitNum" ascending:YES];
//unitNum 相同 按照uIndex屬性 升序排序
NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"uIndex" ascending:YES];
//uIndex 相同 按照onNominalLayer屬性 降序排序
NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"onNominalLayer" ascending:NO];
//給數(shù)組添加排序規(guī)則
[jsonArr sortUsingDescriptors:@[sort,sort1,sort2]];
// NSLog(@"dataArr:%@",[AppHouseInfoModel mj_keyValuesArrayWithObjectArray:dataArr]);
NSDictionary *dict = [jsonArr linq_groupBy:^id(id item) {
ZHItemModel *model = (ZHItemModel *)item;
return [NSString stringWithFormat:@"%ld",model.unitNum];
}];
//key排序
NSMutableArray *unitKeysArr = [NSMutableArray array];
for (NSString *key in dict.allKeys) {
[unitKeysArr addObject:[NSNumber numberWithInteger:key.integerValue]];
}
NSArray *allUnitKeys = [unitKeysArr linq_sort];
for (NSNumber *unitKey in allUnitKeys) {
NSMutableArray *tempArr = [NSMutableArray array];
NSDictionary *unitDict = [[dict objectForKey:unitKey.stringValue] linq_groupBy:^id(id item) {
ZHItemModel *tempModel = (ZHItemModel *)item;
return [NSString stringWithFormat:@"%ld",tempModel.uIndex];
}];
//key排序
NSMutableArray *indexKeysArr = [NSMutableArray array];
for (NSString *key in unitDict.allKeys) {
[indexKeysArr addObject:[NSNumber numberWithInteger:key.integerValue]];
}
NSArray *allIndexKeys = [indexKeysArr linq_sort];
for (NSNumber *indexKey in allIndexKeys) {
NSMutableArray *allLayerArr = [NSMutableArray array];
NSMutableArray *layerArr = [unitDict objectForKey:indexKey.stringValue];
for (int i = 0; i < layersCount; i ++) {
ZHItemModel *placeholderModel = [[ZHItemModel alloc] init];
NSInteger layer = topLayers - i;
if (layer <= 0 && topLayers > 0) {
layer = layer - 1;
}
placeholderModel.physicLayers = layer;
for (ZHItemModel *layerModel in layerArr) {
//符合判斷條件賦值,不再展示空值
if (layerModel.lowerNominalLayer <= layer
&& layer <= layerModel.highNominalLayer) {
placeholderModel = layerModel;
break;
}
}
[allLayerArr addObject:placeholderModel];
}
//去重保存 避免因為樓層合并出現(xiàn)重復(fù)值多的問題
NSArray *distinctLayers = [allLayerArr linq_distinct];
if (distinctLayers.count) {
[tempArr addObject:distinctLayers];
}
}
[dataArr addObject:tempArr];
}
// NSLog(@"modelArr:%@",self.houseArr);
//傳入數(shù)據(jù)
self.topView.allKeysArr = allUnitKeys;
self.chartView.itemModel = layerModel;
self.chartView.allKeysArr = allUnitKeys;
self.chartView.dataArr = dataArr;
}
4、結(jié)尾
下載地址:ZHLinkageChartView,如果有更好的建議歡迎提出,喜歡的話記得給個star嘍!