iOS二级列表,一次只展开一个

网上的二级列表,QQ分组的demo比比皆是,但是适合自己的才是最好了,我自己写了个适合自己用的,记录一下吧。以后用到的话就直接commond + v了

先上gif图

  • 首先是数据
    NSArray *data = @[@{
                          @"title":@"世上事仿佛都经不起后来的推敲",
                          @"cellData":@[@{
                                            @"content":@"诸如,后来你变了"
                                            },
                                        @{
                                            @"content":@"后来我卷了"
                                            }]
                          },
                      @{
                          @"title":@"后来故人零落",
                          @"cellData":@[@{
                                            @"content":@"新人款款前来"
                                            },
                                        @{
                                            @"content":@"后来时光静默"
                                            },
                                        @{
                                            @"content":@"过往逆流成河"
                                            }]
                          },
                      @{
                          @"title":@"模糊的青天雨落",
                          @"cellData":@[@{
                                            @"content":@"遗失的年少轻彻"
                                            },@{
                                            @"content":@"此去的别后经年"
                                            },
                                        @{
                                            @"content":@"他乡的阁楼冷彻"
                                            }]
                          },
                      @{
                          @"title":@"我还倚着些微的坚强",
                          @"cellData":@[@{
                                            @"content":@"却已背离曾经的方向"
                                            },
                                        @{
                                            @"content":@"半盏酒后"
                                            },
                                        @{
                                            @"content":@"便是遗忘"
                                            }]
                          }];
  • 创建model
    HeaderModel.h
#import 
#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 
#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];
}
  • 创建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];
}
//界面重置
- (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];
}
  • 创建SectionHeaderView
    HeaderView.h
#import 
@class HeaderView,HeaderModel;
@protocol HeaderViewDelegate <NSObject>
-(void)selectedWith:(HeaderView *)view;
@end
@interface HeaderView : UIView
@property (nonatomic,weak) id 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];

        //时间
        UILabel *label = [[UILabel alloc]init];
        label.font = [UIFont systemFontOfSize:titleFont] ;
        label.textColor = [UIColor blackColor];
        label.textAlignment = NSTextAlignmentLeft;
        [backView addSubview:label];
        self.label = label;

        //箭头
        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:@"向下箭头-4"] forState:UIControlStateNormal];
        [btn.imageView setContentMode:UIViewContentModeScaleAspectFill];
        [backView addSubview:btn];
        self.backBtn = btn;
    }
    return self;
}

-(void)layoutSubviews
{
    [super layoutSubviews];
    //位置
    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];
    }
}
  • 创建Cell
    Cell.h
#import 
@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) {
        // 添加自己可能显示的所有子控件
        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

最近发现一个问题,就是如果列表数据多了的话,点击最下面的二级列表,tableview就会自动回滚到最上面去,一直以为是刷新了整个tableview导致的,后来发现并不是,给tableview添加这三个属性就好了

      _tableView.estimatedRowHeight = 0;
      _tableView.estimatedSectionHeaderHeight = 0;
      _tableView.estimatedSectionFooterHeight = 0;

简书地址
源码地址,欢迎大家下载

你可能感兴趣的:(iOS二级列表,一次只展开一个)