中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS基于UITableView如何實現多層展開與收起

發布時間:2021-07-15 14:31:19 來源:億速云 閱讀:465 作者:小新 欄目:移動開發

小編給大家分享一下iOS基于UITableView如何實現多層展開與收起,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

規則要求:

  • tableview 有多層,類似于xcode文件目錄的層級關系,每一個最開始展示的層姑且稱之為根目錄吧,并且,每個根目錄下的層數不定。

  • 與文件目錄類似,每個目錄下可以有不同層級的目錄同時展開,但是同一層次中只有一層是展開的,即要展開B層次的某一層,則需要收起B層次所有其他的層級。

  • 最底層是一個個文件,不能再展開(這里在業務邏輯上用處是:跳轉到不同的頁面)。

想法:

  • 整個界面是一個tableview,層級關系用cell中的label的位置展現,而tableview的數據源是一個一維數組_resultArray,其中,展開是在特定位置插入數據,收起是在特定位置刪除數據。

  • 每一層目錄存儲著下一層的引用,就是包含了下一層的全部數據。展開該層的時候就是將下一層的數據加入_resultArray,收起該層時,是將該層的所有下層的數據從_resultArray中刪除。

數據存儲

//每個目錄的數據結構如下:
@interface OpenTest : NSObject
@property (copy, nonatomic) NSString *title;  //非首層展示的標題
@property (assign, nonatomic) NSInteger level; //決定偏移量大小
@property (copy, nonatomic) NSString *openUrl; //最后一層跳轉的規則
@property (copy, nonatomic) NSMutableArray *detailArray; //下一層的數據
@property (assign, nonatomic) BOOL isOpen;    //是否要展開
@property (copy, nonatomic) NSString *imageName; //首層的圖片
@end

其中,因為detailArray中存儲的對象也應該是OpenTest, 所以需要在OpenTest.m中借助MJExtension (在github上下載并加入到項目中)進行顯式轉化。

#import "OpenTest.h"
@implementation OpenTest
- (instancetype)init {
  self = [super init];
  if (self) {
    [OpenTest mj_setupObjectClassInArray:^NSDictionary *{
      return @{
           @"detailArray" : [OpenTest class]
           };
    }];
  }
  return self;
}
@end

數據處理

開始建造源數據dataArray,該數組可明確層級關系,并且得到展示數組_resultArray。建造過程如下:

- (void)initData {
_dataArray = [NSMutableArray new];
_resultArray = [NSMutableArray new];

NSMutableArray *secondArray1 = [NSMutableArray new];
NSMutableArray *threeArray1 = [NSMutableArray new];
NSMutableArray *fourArray1 = [NSMutableArray new];

NSArray *FirstTitleArray = @[@"FirstTitle1", @"FirstTitle2", @"FirstTitle3", @"FirstTitle4", @"FirstTitle5", @"FirstTitle6", @"FirstTitle7", @"FirstTitle8", @"FirstTitle9", @"FirstTitle10"];
NSArray *SecondTitleArray = @[@"SecondTitle1", @"SecondTitle2", @"SecondTitle3"];
NSArray *ThreeTitleArray = @[@"ThreeTitle1", @"ThreeTitle2", @"ThreeTitle3", @"ThreeTitle4"];
NSArray *FourTitleArray = @[@"FourTitle1", @"FourTitle2", @"FourTitle3"];
NSArray *imageArray = @[@"scroller1", @"scroller2", @"scroller3", @"scroller4", @"scroller5", @"scroller6", @"scroller7", @"scroller8", @"scroller9", @"scroller10"];

//第四層數據
for (int i = 0; i < FourTitleArray.count; i++) {
  OpenTest *model = [[OpenTest alloc] init];
  model.title = FourTitleArray[i];
  model.level = 3;
  model.isOpen = NO;

  [fourArray1 addObject:model];
}

//第三層數據
for (int i = 0; i < ThreeTitleArray.count; i++) {
  OpenTest *model = [[OpenTest alloc] init];
  model.title = ThreeTitleArray[i];
  model.level = 2;
  model.isOpen = NO;
  model.detailArray = fourArray1;

  [threeArray1 addObject:model];
}

//第二層數據
for (int i = 0; i < SecondTitleArray.count; i++) {
  OpenTest *model = [[OpenTest alloc] init];
  model.title = SecondTitleArray[i];
  model.level = 1;
  model.isOpen = NO;
  model.detailArray = [threeArray1 mutableCopy];

  [secondArray1 addObject:model];
}

//第一層數據
for (int i = 0; i < FirstTitleArray.count; i++) {
  OpenTest *model = [[OpenTest alloc] init];
  model.title = FirstTitleArray[i];
  model.level = 0;
  model.isOpen = NO;
  model.detailArray = [secondArray1 mutableCopy];
  model.imageName = imageArray[i];

  [_dataArray addObject:model];
}

//處理源數據,獲得展示數組_resultArray
[self dealWithDataArray:_dataArray];
}

/**
 將源數據數組處理成要展示的一維數組,最開始是展示首層的所有的數據
 @param dataArray 源數據數組
 */
- (void)dealWithDataArray:(NSMutableArray *)dataArray {
for (OpenTest *model in dataArray) {
  [_resultArray addObject:model];

  if (model.isOpen && model.detailArray.count > 0) {
    [self dealWithDataArray:model.detailArray];
  }
}
}

當首層沒有展開數據時,點擊首層展開第二層數據,比較容易實現,即在_resultArray添加下一層數據。添加數據方法如下:

/**
 在指定位置插入要展示的數據
 @param dataArray 數據數組
 @param row    需要插入的數組下標
 */
- (void)addObjectWithDataArray:(NSMutableArray *)dataArray row:(NSInteger)row {
for (int i = 0; i < dataArray.count; i++) {
  OpenTest *model = dataArray[i];
  model.isOpen = NO;
  [_resultArray insertObject:model atIndex:row];
  row += 1;
}
}

收起方法實現如下:

/**
 刪除要收起的數據
 @param dataArray 數據
 @param count   統計刪除數據的個數
 @return 刪除數據的個數
 */
- (CGFloat)deleteObjectWithDataArray:(NSMutableArray *)dataArray count:(NSInteger)count {
for (OpenTest *model in dataArray) {
  count += 1;

  if (model.isOpen && model.detailArray.count > 0) {
    count = [self deleteObjectWithDataArray:model.detailArray count:count];
  }

  model.isOpen = NO;

  [_resultArray removeObject:model];
}

return count;
}

在已經展開的時候點擊另外一個目錄,要先收起再展開。因為每個層次只有一個目錄是展開的,所以收起的時候,只需要跟同層次的目錄數據比較,如果是已經打開的,則刪除打開目錄的所有子層。方法如下:

/**
 與點擊同一層的數據比較,然后刪除要收起的數據和插入要展開的數據
 @param model 點擊的cell對應的model
 @param row  點擊的在tableview的indexPath.row,也對應_resultArray的下標
 */
- (void)compareSameLevelWithModel:(OpenTest *)model row:(NSInteger)row {
NSInteger count = 0;
NSInteger index = 0;  //需要收起的起始位置
//如果直接用_resultArray,在for循環為完成之前,_resultArray會發生改變,使程序崩潰。
NSMutableArray *copyArray = [_resultArray mutableCopy];

for (int i = 0; i < copyArray.count; i++) {
  OpenTest *openModel = copyArray[i];
  if (openModel.level == model.level) {
    //同一個層次的比較
    if (openModel.isOpen) {
      //刪除openModel所有的下一層
      count = [self deleteObjectWithDataArray:openModel.detailArray count:count];
      index = i;
      openModel.isOpen = NO;
      break;
    }
  }
}

//插入的位置在刪除的位置的后面,則需要減去刪除的數量。
if (row > index && row > count) {
  row -= count;
}

[self addObjectWithDataArray:model.detailArray row:row + 1];
}

界面

系統的tableviewcell 無法修改textLabel的位置,需要修改偏移量有兩種方法。
1、繼承UITableViewCell, 然后重寫父類的方法 - layoutSubviews, 在該方法中修改textLabel的frame。
2、在cell.contentView 中添加一個label。

我這里使用的是第二種方法:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

  if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(15, 0, UI_SCREEN_WIDTH / 2, 32)];
    label.font = [UIFont systemFontOfSize:14];
    label.tag = LabelTag;

    [cell.contentView addSubview:label];
  }

  for (UIView *view in cell.contentView.subviews) {
    if (view.tag == LabelTag) {
      ((UILabel *)view).text = model.title;
      ((UILabel *)view).frame = CGRectMake(15 + (model.level - 1) * SpaceWidth , 0, UI_SCREEN_WIDTH / 2, 32);
    }
  }

最后在didSelectRowAtIndexPath方法中實現點擊展開與收起,方法如下:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = indexPath.row;
OpenTest *model = _resultArray[row];

if (model.isOpen) {
  //原來是展開的,現在要收起,則刪除model.detailArray存儲的數據
  [self deleteObjectWithDataArray:model.detailArray count:0];
}
else {
  if (model.detailArray.count > 0) {
    //原來是收起的,現在要展開,則需要將同層次展開的收起,然后再展開
    [self compareSameLevelWithModel:model row:row];
  }
  else {
    //點擊的是最后一層數據,跳轉到別的界面
    NSLog(@"最后一層");
  }
}

model.isOpen = !model.isOpen;

//滑動到屏幕頂部
for (int i = 0; i < _resultArray.count; i++) {
  OpenTest *openModel = _resultArray[i];

  if (openModel.isOpen && openModel.level == 0) {
    //將點擊的cell滑動到屏幕頂部
    NSIndexPath *selectedPath = [NSIndexPath indexPathForRow:i inSection:0];
    [tableView scrollToRowAtIndexPath:selectedPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
  }
}

[tableView reloadData];
}

效果

iOS基于UITableView如何實現多層展開與收起

看完了這篇文章,相信你對“iOS基于UITableView如何實現多層展開與收起”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

剑河县| 尼木县| 宜良县| 托里县| 屏山县| 宿州市| 江阴市| 天气| 寿光市| 潍坊市| 韩城市| 舒兰市| 荥阳市| 尖扎县| 肇州县| 安丘市| 德格县| 三台县| 陇西县| 岳普湖县| 苗栗市| 丘北县| 达州市| 桦南县| 蛟河市| 定西市| 曲水县| 四会市| 武邑县| 巨鹿县| 红安县| 舒兰市| 青冈县| 高碑店市| 得荣县| 湖口县| 曲阳县| 襄樊市| 兰州市| 浮梁县| 昂仁县|