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

来源:互联网 发布:淘宝联盟高佣金多少 编辑:程序博客网 时间:2024/06/05 02:31

前言

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
原创粉丝点击