【Demo】UITableView实现分组可折叠下拉列表

前言

UITableView作为UIKit中最重要的一个组件,应用还是很广泛很灵活的,它的特性用来实现分组列表再合适不过。可折叠分组列表最典型的是好友列表,是一个二级目录,点击每一个分组都会展开或折叠一个好友列表。
这里使用TableView的section header作为分组一级目录,每个section的cell作为二级目录。section header里面放的是一个自定义的UIButton,button的图片设置为折叠指示箭头,button的文字为分组名称,为这个button定义代理,点击按钮时通知刷新对应的section的数据即可展开或者折叠该分组。

这里写图片描述

自定义section header头部按钮以及协议

头部按钮的制作主要有三点:一个是定义点击后的通知代理,二是调整按钮图片和文字的frame成左图右文字的样式(通过contentRect代理回调来调整),三是点击后按钮图片的旋转动画(tranform旋转90)。

//
//  SectionHeaderView.h
//  JXHDemo
//
//  Created by 919575700@qq.com on 10/23/15.
//  Copyright (c) 2015 Jiangxh. All rights reserved.
//  section头部视图,是一个buntton

#import <UIKit/UIKit.h>

@class SectionHeaderView;
/**
 * 自定义协议
 */
@protocol SectionHeaderDelegate <NSObject>

//点击了section header
- (void)sectionDidClicked:(SectionHeaderView *)sender;

@end

@interface SectionHeaderView : UIButton

/**
 *  记录是否已经展开
 */
@property (nonatomic)BOOL isOpen;

/**
 *  协议
 */
@property (nonatomic, weak) id<SectionHeaderDelegate>delegate;

@end
//
//  SectionHeaderView.m
//  JXHDemo
//
//  Created by 919575700@qq.com on 10/23/15.
//  Copyright (c) 2015 Jiangxh. All rights reserved.
//
#define sectionMargin 10
#define sectionIconSize 20
#import "SectionHeaderView.h"

@interface SectionHeaderView()

@end

@implementation SectionHeaderView

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        //设置按钮属性
        [self setButton];
    }
    return self;
}

/**
 *  设置按钮属性
 */
- (void)setButton {
    _isOpen = NO;
    //背景色
    self.backgroundColor = [UIColor whiteColor];
    // 文字颜色
    [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

    // 添加指示图片
    [self setImage:[UIImage imageNamed:@"arrow"] forState:UIControlStateNormal];
    // 图片模式
    self.imageView.contentMode = UIViewContentModeScaleAspectFit;

    // 添加下分割线
    UIImageView *underLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.frame.size.height-1, self.frame.size.width, 1)];
    // 贴图
    [underLine setImage:[UIImage imageNamed:@"line"]];
    //改变线的透明度
    [underLine setAlpha:0.3];
    [self addSubview:underLine];

    // 添加点击事件
    [self addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];

}

/**
 *  点击
 */
- (void)clicked:(SectionHeaderView *)sender {

    // 如果没展开,顺时针旋转90度
    if (!_isOpen) {
        [sender.imageView setTransform:CGAffineTransformMakeRotation(M_PI_2)];
    }
    // 如果展开了,逆时针旋转90度
    else {
        [sender.imageView setTransform:CGAffineTransformMakeRotation(-M_PI_2)];
    }

    // 通知代理
    [_delegate sectionDidClicked:sender];

    // 状态取反
    _isOpen = !_isOpen;
}

/**
 *  返回代理需要的标题尺寸和图片尺寸
 */
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
    return CGRectMake(55, 0, contentRect.size.width, contentRect.size.height);
}
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    return CGRectMake(20, 5, contentRect.size.height-10, contentRect.size.height-10);
}

@end

自定义cell

cell的样式根据需要可以随便设计,这里设置一个最简单的:一个头像,一个名字。

//
//  AccountCell.h
//  JXHDemo
//
//  Created by Xinhou Jiang on 3/11/16.
//  Copyright © 2016年 Jiangxh. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface AccountCell : UITableViewCell

// 头像
@property (nonatomic, strong) UIImageView *avatar;

// 昵称
@property (nonatomic, strong) UILabel *name;

@end
//
//  AccountCell.m
//  JXHDemo
//
//  Created by Xinhou Jiang on 3/11/16.
//  Copyright © 2016年 Jiangxh. All rights reserved.
//
#define cellH 40 // cell高度
#define ApplicationW [UIScreen mainScreen].bounds.size.width // 屏幕宽度

#import "AccountCell.h"

@implementation AccountCell

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // 头像
        _avatar = [[UIImageView alloc]initWithFrame:CGRectMake(5, 5, cellH-10, cellH-10)];
        _avatar.layer.cornerRadius = (cellH-10)/2;
        [self.contentView addSubview:_avatar];

        // 账号
        _name = [[UILabel alloc]initWithFrame:CGRectMake(cellH, 0, ApplicationW - cellH, cellH)];
        _name.font = [UIFont systemFontOfSize:12.0];
        [self.contentView addSubview:_name];
    }

    return self;
}

@end

数据模型

数据主要是section分组的一个数据数组和每个分组的cell数据数组,这里为了简单固定返回了一组死数据,具体有了数据源在request的函数内将数据对应接入即可。

/**
 *  记录section的展开状态
 */
@property (nonatomic, strong)NSMutableArray *isOpen;

/**
 *  记录section的标题数组
 */
@property (nonatomic, strong)NSArray *titles;

/**
 *  请求数据
 */
- (void)initValue {
    // 标题数组假数据
    _titles = @[@"朋友", @"同学", @"家人", @"同事"];

    // 初始化所有section都是折叠状态
    _isOpen = [[NSMutableArray alloc] initWithCapacity:_titles.count];
    for (int i = 0; i<_titles.count; i++) {
        [_isOpen addObject:@NO];
    }
}


/**
 *  cell
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *identifier = @"identifier";
    // 具体可以自制cell组件
    AccountCell *cell = [[AccountCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    // 头像,具体应该从好友数据中取
    [cell.avatar setImage:[UIImage imageNamed:@"male"]];
    // 昵称,具体应该从好友数据中取
    cell.name.text = @"夏明";
    //cell颜色
    //cell.backgroundColor = RGBColor(200, 200, 200);

    return cell;
}

UITableView分组下拉列表

主体就是TableView的一个完整应用,包括section和cell的管理。

//
//  FolderTableViewController.h
//  JXHDemo
//
//  Created by 919575700@qq.com on 10/23/15.
//  Copyright (c) 2015 Jiangxh. All rights reserved.
//  可折叠section的表格

#import <UIKit/UIKit.h>

@interface FolderTableViewController : UITableViewController

@end
//
//  FolderTableViewController.m
//  JXHDemo
//
//  Created by 919575700@qq.com on 10/23/15.
//  Copyright (c) 2015 Jiangxh. All rights reserved.
//
#define sectionHeaderH 30 //组头部的高度
#define ApplicationW [UIScreen mainScreen].bounds.size.width // 屏幕宽度
#define RGBColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] // 通过RGB创建颜色

#import "FolderTableViewController.h"
#import "SectionHeaderView.h"
#import "AccountCell.h"

@interface FolderTableViewController ()<SectionHeaderDelegate>

/**
 *  记录section的展开状态
 */
@property (nonatomic, strong)NSMutableArray *isOpen;

/**
 *  记录section的标题数组
 */
@property (nonatomic, strong)NSArray *titles;

@end

@implementation FolderTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 表格基本设置
    self.title = @"可展开的TableView";
    self.view.backgroundColor = RGBColor(240, 240, 240);
    // 清除底部多余cell
    [self.tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]];
    // 清除分割线
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

    // 请求数据
    [self initValue];
}

/**
 *  请求数据
 */
- (void)initValue {
    // 标题数组假数据
    _titles = @[@"朋友", @"同学", @"家人", @"同事"];

    // 初始化所有section都是折叠状态
    _isOpen = [[NSMutableArray alloc] initWithCapacity:_titles.count];
    for (int i = 0; i<_titles.count; i++) {
        [_isOpen addObject:@NO];
    }
}

#pragma mark - 组设置
/**
 *  多少组
 */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return _titles.count;
}
/**
 *  section header的高度
 */
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return sectionHeaderH;
}
/**
 *  section header的视图
 */
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    // section头部视图
    SectionHeaderView *sectionHeader = [[SectionHeaderView alloc] initWithFrame:CGRectMake(0, 0, ApplicationW, sectionHeaderH)];
    // 标题
    [sectionHeader setTitle:[_titles objectAtIndex:section] forState:UIControlStateNormal];
    // 为headerview打上tag
    [sectionHeader setTag:section];
    // 代理
    sectionHeader.delegate = self;

    return sectionHeader;
}
#pragma mark SectionHeader实现代理
/**
 *  实现代理,sectionheader 点击
 */
- (void)sectionDidClicked:(SectionHeaderView *)sender {

    // 取反状态
    BOOL reverse = ![_isOpen[sender.tag] boolValue];
    _isOpen[sender.tag] = [NSNumber numberWithBool:reverse];

    /***  这里刷新后section的header也会被刷新,导致指示箭头又恢复到旋转之前的状态,待解决  ***/
    // 刷新点击的分区(展开或折叠)
    [self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:sender.tag] withRowAnimation:UITableViewRowAnimationNone];
}

#pragma mark - 组内行设置
/**
 *  每组多少行
 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if ([_isOpen[section] boolValue]) {
        return 5; // 具体应该返回该分组好友的个数
    }else {
        return 0;
    }
}
/**
 *  cell
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *identifier = @"identifier";
    // 具体可以自制cell组件
    AccountCell *cell = [[AccountCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    // 头像,具体应该从好友数据中取
    [cell.avatar setImage:[UIImage imageNamed:@"male"]];
    // 昵称,具体应该从好友数据中取
    cell.name.text = @"夏明";
    //cell颜色
    //cell.backgroundColor = RGBColor(200, 200, 200);

    return cell;
}

@end

组件的调用

组件的使用很简单,一句话加入,引入TavleViewController类,实例化为一个子viewcontroller即可。

- (void)viewDidLoad {
    [super viewDidLoad];

    // 显示折叠视图
    FolderTableViewController *foldableVC = [[FolderTableViewController alloc]init];
    [self addChildViewController:foldableVC];
    [self.view addSubview:foldableVC.view];

}

这里写图片描述

存在的问题(待解决)

存在的一个问题是,点击分组按钮时,刷新的是整个section,包括头部的header按钮,因此虽然头部按钮点击后箭头旋转了,但由于马上被更新了换了新的头部按钮,导致箭头看上去没有反应,而TableView并没有只更新某个section的所有cell而不更新section的header的方法。暂时没有想到比较优雅的解决办法,探索中…orz

Demo下载(不想花积分的请回复邮箱)
http://download.csdn.net/detail/cordova/9673964

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr_厚厚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值