美文网首页iOS 开发技巧iOSiOS学习开发
【Objective-c】UITableView 折叠效果

【Objective-c】UITableView 折叠效果

作者: MR_詹 | 来源:发表于2016-11-05 10:40 被阅读3751次

    小编敲代码实现项目功能时,心中总会打上许多问号“ ?”,虽然项目的UI和功能都实现了,但总觉得自己的方法很low,没有什么复用度和设计模式可言,处于低级阶段,离高新的目标很是遥远!!!更不要说迎娶白富美了"~".......好了,扯了有点远了,言归正传:UITableView折叠效果(类似QQ联系人的折叠),在没有看到大神博客的时候,

    我实现的套路如下:
    1、使用Xib定制两个Cell(一个标题Cell,一个展开Cell)
    2、折叠展开是通过改变tableView的section分区中cell的个数,折叠时数量1,展开时数  量就有多个
    3、两个重要参数:一个NSArray存储内容(后台数据请求返回的),
                                   一个NSDictionary记录“折叠展开”
    4、改变“折叠”“展开状态”,通过刷新整个tableIView展示
    

    不足的是:
    1、在cellForRow方法中要判断是标题Cell还是展开Cell
    2、在cell的点击方法中也是需要判断是标题Cell还是展开Cell
    3、刷新整个tableView,消耗的资源比较大(当然可以只是刷新某个section)

    虽然实现的代码量不多,逻辑也不复杂,但是要知道项目是会成长的,后续添加的功能需求只会越来越多,这就考验当初设计时:代码的灵活度、代码的分工明不明细(影响代码的可读性)、代码的扩展性等等,这就是我们经常看到一些大神在实现一些简单功能的时候总会创建几个分类,然后跳来跳去的,心中就疑惑就起来了.....

    接下来谈谈大神的方法(面向对象的编程思想)

    1、依然是通过改变tableView的section分区中cell的个数,不同的是折叠时为0,展开时是多个,因为布局中标题cell是在每个section的头视图显示的(这样在cellForRow中就不需要判断)
    2、创建UITableViewHeaderFooterView的子类,自定义标题内容
    3、自定义cell,显示展开后的cell
    4、创建section模型,存储每组section的内容
    5、创建cell模型,存储展开后每个cell的内容
    6、单独刷新section

    详情请看代码:

    先看效果图,有个概念


    spring.gif
    建立模型:
    @interface SectionModel : NSObject
    @property (nonatomic,assign) BOOL isExpand;
    @property (nonatomic,strong) NSString *title;
    @property (nonatomic,strong) NSArray *cellArray;
    @end
    
    @interface CellModel : NSObject
    @property (nonatomic,strong) NSString *title;
    @end
    
    创建一个继承于UITableViewHeaderFooterView的子类"SectionView"
    @class SectionModel;
    typedef void(^CallBackBlock)(BOOL);
    @interface SectionView : UITableViewHeaderFooterView
    @property (nonatomic,strong) SectionModel *model;
    @property (nonatomic,strong) CallBackBlock block;
    @end
    

    .m文件

    /* 在构造方法中,创建UI*/
    - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier{
        if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
            CGFloat w = [UIScreen mainScreen].bounds.size.width;
            self.arrowImage = [[UIImageView alloc]initWithFrame:CGRectMake(10, (44 - 8) / 2, 15, 8)];
            self.arrowImage.image = [UIImage imageNamed:@"right.png"];
            [self.contentView addSubview:self.arrowImage];
            
            UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, w, 44)];
            [button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
            [self.contentView addSubview:button];
            
            self.titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(30, (44 - 20) / 2, w-20, 20)];
            self.titleLabel.font = [UIFont systemFontOfSize:17];
            self.titleLabel.textColor = [UIColor blackColor];
    
            UIView *line = [[UIView alloc]initWithFrame:CGRectMake(0, 43, w, 1)];
            line.backgroundColor = [UIColor darkGrayColor];
            [self.contentView addSubview:line];
            
            [self.contentView addSubview:self.titleLabel];
            
            self.contentView.backgroundColor = [UIColor yellowColor];
        }
        return self;
    }
    
    /*
      1、通过懒加载,设置“箭头”的方向
      2、通过头视图SectionView的点击,改变“箭头”的方向
      3、通过点击SectionView,回调block进行section刷新
    */
    - (void)setModel:(SectionModel *)model{
        if (_model != model) {
            _model = model;
        }
        self.titleLabel.text = model.title;
        if (model.isExpand) {       //展开
            self.arrowImage.transform = CGAffineTransformIdentity;
        }else{
            self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
        }
    }
    
    - (void)btnClick:(UIButton *)sender{
        self.model.isExpand = ! self.model.isExpand;
        if (self.model.isExpand) {
            self.arrowImage.transform = CGAffineTransformIdentity;
        }else{
            self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
        }
        if (self.block) {
            self.block(self.model.isExpand);
        }
    }
    
    tableView 的配置
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
    @property (nonatomic,strong) UITableView *tableView;
    @property (nonatomic,strong) NSMutableArray *sectionData;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.tableView = [[UITableView alloc]initWithFrame:self.view.frame style:UITableViewStylePlain];
        self.tableView.delegate = self;
        self.tableView.dataSource = self;
        [self.view addSubview:self.tableView];
        
        [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellid"];
        [self.tableView registerClass:[SectionView class] forHeaderFooterViewReuseIdentifier:@"header"];
    }
    //懒加载
    - (NSMutableArray *)sectionData{
        if (_sectionData == nil) {
            _sectionData = [[NSMutableArray alloc]init];
            for (int i=0; i<20; i++) {
                SectionModel *model = [[SectionModel alloc]init];
                model.title = [NSString stringWithFormat:@"%d",i];
                model.isExpand = NO;
                NSMutableArray *array = [[NSMutableArray alloc]init];
                for (int j=0; j<10; j++) {
                    CellModel *cell = [[CellModel alloc]init];
                    cell.title = [NSString stringWithFormat:@"LivenCell==Section:%d,Row:%d",i,j];
                    [array addObject:cell];
                }
                model.cellArray = array;
                [_sectionData addObject:model];
            }
        }
        return _sectionData;
    
    }
    #pragma mark - tableView delegate
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return self.sectionData.count;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        SectionModel *model = _sectionData[section];
        return model.isExpand?model.cellArray.count:0;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellid"];
        SectionModel *section = _sectionData[indexPath.section];
        CellModel *model = section.cellArray[indexPath.row];
        cell.textLabel.text = model.title;
        return cell;
    }
    
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
        SectionView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"header"];
        SectionModel *model = _sectionData[section];
        view.model = model;
        //更变了section的cell数量,所以要刷新
        view.block = ^(BOOL isExpanded){
            [tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
        };
        return view;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return 44;
    }
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
        return 44;
    }
    

    整体的内容就这么多,这个Demo真的不错,觉得好的自己多敲几遍,最后必须感谢“标哥”对我的启发

    相关文章

      网友评论

      • 流水孤村:展开后箭头向下,在展开的状态刷新,箭头还是向下,是不是bug
      • Coder_Melo:非常棒,面向对象的思想
      • Frey丶:能分享下demo吗? :smile:
      • 收麦子的人:如果是三层,什么思路?比如省份、市、县
        清無:@LLLLLLLLUO 也可以嵌套继续,cell+tableview

      本文标题: 【Objective-c】UITableView 折叠效果

      本文链接:https://www.haomeiwen.com/subject/ybowuttx.html