There are many secondary lists and QQ group demo s on the Internet, but the best one is the one that suits me. I wrote a one that suits me. Record it. In the future, you can use common D + V directly
gif chart first
- The first is data
NSArray *data = @[@{
@"title":@"Nothing in the world seems to stand up to the scrutiny later",
@"cellData":@[@{
@"content":@"For example, later you changed"
},
@{
@"content":@"And then I did"
}]
},
@{
@"title":@"Later, my old friends were scattered",
@"cellData":@[@{
@"content":@"New people come here"
},
@{
@"content":@"And then there was silence"
},
@{
@"content":@"The past turns into a river"
}]
},
@{
@"title":@"The misty blue sky and rain",
@"cellData":@[@{
@"content":@"Lost youth"
},@{
@"content":@"The rest of the year"
},
@{
@"content":@"The attic in another country is cold"
}]
},
@{
@"title":@"I still rely on a little bit of strength",
@"cellData":@[@{
@"content":@"But it has deviated from its former direction"
},
@{
@"content":@"Half a bottle of wine"
},
@{
@"content":@"Forgotten."
}]
}];
- Create model
HeaderModel.h
#import <Foundation/Foundation.h>
#import "CellModel.h"
@interface HeaderModel : NSObject
@property (nonatomic,copy) NSString *title;
@property (nonatomic,strong) NSArray *cellData;
@end
HeaderModel.m
#import "HeaderModel.h"
@implementation HeaderModel
+(NSDictionary *)mj_objectClassInArray
{
return @{
@"cellData":@"CellModel"
};
}
@end
CellModel.h
#import <Foundation/Foundation.h>
#import "MJExtension.h"
@interface CellModel : NSObject
@property (nonatomic,copy) NSString *content;
@end
CellModel.m
#import "CellModel.h"
@implementation CellModel
MJCodingImplementation
@end
- UIViewController
#import "ViewController.h"
#import "HeaderModel.h"
#import "Cell.h"
#import "CellModel.h"
#import "HeaderView.h"
@interface ViewController ()
<UITableViewDelegate,UITableViewDataSource,HeaderViewDelegate>
{
int _currentRow;
int _currentSection;
}
@property (nonatomic, strong)UITableView *tableView;
@property(nonatomic,strong)NSMutableArray * headViewArray;
@property (nonatomic,strong) NSMutableArray *data;
@end
@implementation ViewController
-(NSMutableArray *)data
{
if (!_data) {
_data = [NSMutableArray array];
}
return _data;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.data = [HeaderModel mj_objectArrayWithKeyValuesArray:data];
self.headViewArray = [NSMutableArray array];
int i = 0;
for (HeaderModel *model in self.data) {
HeaderView *headerView = [[HeaderView alloc]init];
headerView.headerModel = model;
headerView.delegate = self;
headerView.index = i;
i++;
[self.headViewArray addObject:headerView];
}
[self.view addSubview:self.tableView];
}
- Create tableView
-(UITableView *)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 10, self.view.width, self.view.height - 20) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;
_tableView.backgroundColor = [UIColor whiteColor];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return _tableView;
}
- UITableviewDelegateâUITableviewDataSource
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return self.headViewArray[section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
HeaderView* headView = self.headViewArray[section];
HeaderModel *headerModel = self.data[section];
return headView.open?headerModel.cellData.count:0;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [self.headViewArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *cell = [Cell cellWithTableView:tableView];
HeaderModel *headerModel = self.data[indexPath.section];
CellModel *model = headerModel.cellData[indexPath.row];
cell.model = model;
return cell;
}
-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
return 50;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(@"click---%ld section and %ld row",(long)indexPath.section,(long)indexPath.row);
}
#pragma mark - HeadViewdelegate
-(void)selectedWith:(HeaderView *)view{
_currentRow = -1;
if (view.open) {
for(int i = 0;i<[self.headViewArray count];i++)
{
HeaderView *head = [self.headViewArray objectAtIndex:i];
head.open = NO;
[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
head.backBtn.layer.transform = CATransform3DMakeRotation(0, 0, 0, 1);
} completion:NULL];
}
[_tableView reloadData];
return;
}
_currentSection = (int)view.index;
[self reset];
}
//Interface reset
- (void)reset
{
for(int i = 0;i<[self.headViewArray count];i++)
{
HeaderView *head = [self.headViewArray objectAtIndex:i];
if(head.index == _currentSection)
{
head.open = YES;
[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
head.backBtn.layer.transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
} completion:NULL];
}else {
[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
head.backBtn.layer.transform = CATransform3DMakeRotation(0, 0, 0, 1);
} completion:NULL];
head.open = NO;
}
}
[_tableView reloadData];
}
- Create SectionHeaderView
HeaderView.h
#import <UIKit/UIKit.h>
@class HeaderView,HeaderModel;
@protocol HeaderViewDelegate <NSObject>
-(void)selectedWith:(HeaderView *)view;
@end
@interface HeaderView : UIView
@property (nonatomic,weak) id<HeaderViewDelegate> delegate;
@property(nonatomic, assign) NSInteger index;
@property(nonatomic, assign) BOOL open;
@property(nonatomic, retain) UIButton* backBtn;
@property(nonatomic, strong) HeaderModel * headerModel;
@end
HeaderView.m
#import "HeaderView.h"
#import "UIView+Extension.h"
#import "HeaderModel.h"
@interface HeaderView()
@property (nonatomic,strong) UIView *backView;
@property (nonatomic,weak) UILabel *label;
@end
@implementation HeaderView
-(instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
_open = NO;
CGFloat titleFont = 15;
self.backgroundColor = [UIColor whiteColor];
UIView *backView = [[UIView alloc]init];
backView.backgroundColor = [UIColor whiteColor];
self.backView = backView;
[self addSubview:backView];
//time
UILabel *label = [[UILabel alloc]init];
label.font = [UIFont systemFontOfSize:titleFont] ;
label.textColor = [UIColor blackColor];
label.textAlignment = NSTextAlignmentLeft;
[backView addSubview:label];
self.label = label;
//Arrow
UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn addTarget:self action:@selector(doSelected) forControlEvents:UIControlEventTouchUpInside];
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSelected)]];
[btn setImage:[UIImage imageNamed:@"down arrow-4"] forState:UIControlStateNormal];
[btn.imageView setContentMode:UIViewContentModeScaleAspectFill];
[backView addSubview:btn];
self.backBtn = btn;
}
return self;
}
-(void)layoutSubviews
{
[super layoutSubviews];
//position
self.backView.frame = CGRectMake(0, 5, self.width, self.height - 10);
self.label.frame = CGRectMake(10, (self.backView.height - 40)/2, self.backView.width - 60, 40);
self.backBtn.frame = CGRectMake(self.width - self.height +10, 0, self.height - 10, self.height - 10);
}
-(void)setHeaderModel:(HeaderModel *)headerModel
{
_headerModel = headerModel;
self.label.text = headerModel.title;
}
-(void)doSelected{
if (_delegate && [_delegate respondsToSelector:@selector(selectedWith:)]){
[_delegate selectedWith:self];
}
}
- Create Cell
Cell.h
#import <UIKit/UIKit.h>
@class CellModel;
@interface Cell : UITableViewCell
+(instancetype)cellWithTableView:(UITableView *)tableView;
@property (nonatomic,strong) CellModel *model;
@end
Cell.m
#import "Cell.h"
#import "CellModel.h"
#import "UIView+Extension.h"
@interface Cell ()
@property (nonatomic,weak) UILabel *piCiLabel;
@end
@implementation Cell
+(instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *CellID = @"Cell";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];
if (cell == nil) {
cell = [[Cell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Add all the child controls you may display
self.backgroundColor = [UIColor whiteColor];
UILabel *piCiLabel = [[UILabel alloc]init];
piCiLabel.font = [UIFont systemFontOfSize:14] ;
piCiLabel.textColor = [UIColor lightGrayColor];
piCiLabel.textAlignment = NSTextAlignmentLeft;
[self.contentView addSubview:piCiLabel];
self.piCiLabel = piCiLabel;
}
return self;
}
-(void)setModel:(CellModel *)model
{
_model = model;
self.piCiLabel.text = model.content;
}
-(void)layoutSubviews
{
[super layoutSubviews];
self.piCiLabel.frame = CGRectMake(20, (self.height - 40)/2, self.width - 25, 40);
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
Recently, I found a problem. If there is more data in the list, click the second level list at the bottom, and the tableview will automatically roll back to the top. I always thought it was caused by refreshing the entire tableview. Later, I found that it was not. Just add these three attributes to the tableview
_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;