需求:类似于QQ好友列表页面的显示,有好友分组,有好友数量,在线人数,vip会员、展开分组时显示分组好友,合并分组时不显示:具体效果图如下:
分析:
1、展开分组时显示分组好友,该功能可以使用显示UITableViewCell的数据即可;
2、分组头可以考虑使用一个headerView来实现;
示例文件结构:
具体实现步骤:
1、自定义数据模型类,由于plist文件中包含了2个字典,所以需要写2个数据模型;
2、自定义cell,属性包括数据模型以及生成可重用cell的方法,由于系统自带的子控件即可满足实际要求,所以不用写frame模型了;
4、自定义HeaderView,包括模型数据属性和快速构造HeaderView的类方法,以及代理方法;
5、在控制器中写UITableView的 数据显示的方法;
具体代码:
Model:
1 // 2 // JWFriend.h 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface JWFriend : NSObject 12 @property (nonatomic,copy) NSString *icon; 13 @property (nonatomic,copy) NSString *intro; 14 @property (nonatomic,copy) NSString *name; 15 @property (nonatomic,assign,getter=isVip) BOOL vip; 16 - (instancetype)initWithDic:(NSDictionary *)dic; 17 + (instancetype)friendWithDic:(NSDictionary *)dic; 18 @end
1 // 2 // JWFriend.m 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import "JWFriend.h" 10 11 @implementation JWFriend 12 - (instancetype)initWithDic:(NSDictionary *)dic { 13 if (self = [super init]) { 14 [self setValuesForKeysWithDictionary:dic];//KVC的使用 15 } 16 return self; 17 } 18 + (instancetype)friendWithDic:(NSDictionary *)dic { 19 return [[self alloc] initWithDic:dic]; 20 } 21 @end
1 // 2 // JWFriendGroup.h 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface JWFriendGroup : NSObject 12 @property (nonatomic,strong) NSArray *friends; 13 @property (nonatomic,copy) NSString *name; 14 @property (nonatomic,assign) int online; 15 /* 16 组头是否展开,默认为NO 17 */ 18 @property (nonatomic,assign,getter=isExpend) BOOL expend; 19 - (instancetype)initWithDic:(NSDictionary *)dic; 20 + (instancetype)friendGroupWithDic:(NSDictionary *)dic; 21 + (NSMutableArray *)friendGroupList; 22 @end
1 // 2 // JWFriendGroup.m 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import "JWFriendGroup.h" 10 #import "JWFriend.h" 11 @implementation JWFriendGroup 12 - (instancetype)initWithDic:(NSDictionary *)dic { 13 if (self = [super init]) { 14 [self setValuesForKeysWithDictionary:dic]; 15 } 16 return self; 17 } 18 + (instancetype)friendGroupWithDic:(NSDictionary *)dic { 19 return [[self alloc] initWithDic:dic]; 20 } 21 22 + (NSMutableArray *)friendGroupList { 23 NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends" ofType:@"plist"]]; 24 25 NSMutableArray *tempArray = [NSMutableArray array]; 26 27 for (NSDictionary *dic in array) {//字典转模型 28 JWFriendGroup *friendGroup = [JWFriendGroup friendGroupWithDic:dic]; 29 30 NSMutableArray *tem = [NSMutableArray array]; 31 for (NSDictionary *dict in friendGroup.friends) {//模型里面还带有子弹,所以继续进行字典转模型步骤 32 JWFriend *friend = [JWFriend friendWithDic:dict]; 33 [tem addObject:friend]; 34 } 35 friendGroup.friends = tem;//转完模型后记得重新赋值 36 [tempArray addObject:friendGroup]; 37 } 38 return tempArray; 39 } 40 @end
View:
1 // 2 // JWFriendCell.h 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 @class JWFriend; 11 @interface JWFriendCell : UITableViewCell 12 @property (nonatomic,strong) JWFriend *friendDatas; 13 + (instancetype)cellWithTableView:(UITableView *)tableView; 14 @end
1 // 2 // JWFriendCell.m 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import "JWFriendCell.h" 10 #import "JWFriend.h" 11 @implementation JWFriendCell 12 //快速构造一个可重用的cee 13 + (instancetype)cellWithTableView:(UITableView *)tableView { 14 static NSString *resue = @"cell"; 15 JWFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:resue]; 16 if (!cell) { 17 cell = [[self alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:resue]; 18 } 19 return cell; 20 } 21 //重写set方法,给各子控件赋值 22 - (void)setFriendDatas:(JWFriend *)friendDatas { 23 _friendDatas = friendDatas; 24 self.textLabel.text = friendDatas.name; 25 self.detailTextLabel.text = friendDatas.intro; 26 self.imageView.image = [UIImage imageNamed:friendDatas.icon]; 27 self.textLabel.textColor = friendDatas.isVip ? [UIColor redColor] : [UIColor blackColor];//如果是vip,那么呢称字体为红色 28 } 29 @end
1 // 2 // JWFriendHeaderView.h 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 @class JWFriendGroup,JWFriendHeaderView; 11 @protocol JWFriendHeaderViewDelegate <NSObject> 12 @optional 13 - (void)clickNameBtn:(JWFriendHeaderView *)headerView; 14 15 @end 16 @interface JWFriendHeaderView : UITableViewHeaderFooterView 17 @property (nonatomic,strong) JWFriendGroup *friendGroup; 18 @property (nonatomic,assign) id<JWFriendHeaderViewDelegate> delegate; 19 + (instancetype)headerViewWithTableView:(UITableView *)tableView; 20 @end
1 // 2 // JWFriendHeaderView.m 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import "JWFriendHeaderView.h" 10 #import "JWFriendGroup.h" 11 @interface JWFriendHeaderView () 12 @property (nonatomic,weak) UIButton *nameView; 13 @property (nonatomic,weak) UILabel *countLabel; 14 @end 15 @implementation JWFriendHeaderView 16 //快速构造一个可重用的组头 17 + (instancetype)headerViewWithTableView:(UITableView *)tableView { 18 static NSString *resue = @"head";//缓存池标识 19 JWFriendHeaderView *headerView = [tableView dequeueReusableCellWithIdentifier:resue]; 20 if (!headerView) { 21 headerView = [[self alloc] initWithReuseIdentifier:resue]; 22 } 23 return headerView; 24 } 25 //重写方法,初始化控件 26 - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier { 27 if (self = [super initWithReuseIdentifier:reuseIdentifier]) { 28 UIButton *nameBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 29 [self.contentView addSubview:nameBtn]; 30 self.nameView = nameBtn; 31 //按钮的一些属性的设置 32 [nameBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 33 [nameBtn setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal]; 34 [nameBtn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal]; 35 [nameBtn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted]; 36 nameBtn.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);//按钮内容的间距,左间距为10 37 nameBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);//文字内容的间距,左间距为10 38 nameBtn.imageView.contentMode = UIViewContentModeCenter;//不缩放按钮图片 39 nameBtn.imageView.clipsToBounds = NO;//图片超出部分不裁剪 40 nameBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;//设置左对齐 41 [nameBtn addTarget:self action:@selector(nameClick) forControlEvents:UIControlEventTouchUpInside];//注册按钮点击事件 42 43 UILabel *countLabel = [[UILabel alloc] init]; 44 [self.contentView addSubview:countLabel]; 45 self.countLabel = countLabel; 46 //文本标签的一些属性的设置 47 countLabel.textAlignment = NSTextAlignmentRight; 48 countLabel.font = [UIFont systemFontOfSize:14]; 49 countLabel.textColor = [UIColor grayColor]; 50 } 51 return self; 52 } 53 //这个方法改变了组头的frame后就会调用,那么可以在这里设置frame了 54 - (void)layoutSubviews { 55 [super layoutSubviews];//记得必须先实现父类的该方法 56 self.nameView.frame = self.bounds; 57 CGFloat countX = self.bounds.size.width - 10 - 150; 58 self.countLabel.frame = CGRectMake(countX, 0, 150, 44); 59 } 60 //点击组头按钮事件 61 - (void)nameClick { 62 self.friendGroup.expend = !self.friendGroup.isExpend;//获取组头是否展开状态 63 [self expend];//调用封装的一个方法,如果展开,那么图片旋转90度,否则不展开 64 if ([self.delegate respondsToSelector:@selector(clickNameBtn:)]) {//通知代理,点击了组头按钮 65 [self.delegate clickNameBtn:self]; 66 } 67 } 68 //重写set方法,给各控件赋值 69 - (void)setFriendGroup:(JWFriendGroup *)friendGroup { 70 _friendGroup = friendGroup;//这句记得写,否则会造成没有内容显示 71 [self.nameView setTitle:friendGroup.name forState:UIControlStateNormal]; 72 self.countLabel.text = [NSString stringWithFormat:@"%d/%lu",friendGroup.online,(unsigned long)friendGroup.friends.count]; 73 [self expend];//调用封装的一个方法,如果展开,那么图片旋转90度,否则不展开 74 } 75 //封装的方法,如果展开,那么图片旋转90度,否则旋转度为0 76 - (void)expend { 77 CGFloat angle = self.friendGroup.isExpend ? M_PI_2 : 0; 78 [UIView animateWithDuration:0.5 animations:^{ 79 self.nameView.imageView.transform = CGAffineTransformMakeRotation(angle); 80 }]; 81 } 82 @end
Controller:
1 // 2 // ViewController.m 3 // 12-24-FriendGroup 4 // 5 // Created by xiaomoge on 14/12/24. 6 // Copyright (c) 2014年 xiaomoge. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "JWFriend.h" 11 #import "JWFriendGroup.h" 12 #import "JWFriendHeaderView.h" 13 #import "JWFriendCell.h" 14 @interface ViewController () <JWFriendHeaderViewDelegate> 15 @property (nonatomic,strong) NSArray *friendGroup; 16 @end 17 18 @implementation ViewController 19 #pragma mark - 隐藏状态栏 20 - (BOOL)prefersStatusBarHidden { 21 return YES; 22 } 23 #pragma mark - 懒加载 24 - (NSArray *)friendGroup { 25 if (!_friendGroup) { 26 _friendGroup = [JWFriendGroup friendGroupList]; 27 } 28 return _friendGroup; 29 } 30 - (void)viewDidLoad { 31 [super viewDidLoad]; 32 //设置组头的高度 33 self.tableView.sectionHeaderHeight = 44; 34 } 35 #pragma mark - tableViewDatasouce的方法 36 //显示多少组数据 37 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 38 return self.friendGroup.count; 39 } 40 //每组数据显示多少行数据 41 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 42 return [self.friendGroup[section] isExpend ]?[self.friendGroup[section] friends].count : 0;//这里使用了三目运算符,主要是判断如果组头是展开的,那么显示行数据,否则显示为0 43 } 44 //显示每个cell的内容 45 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 46 JWFriendCell *cell = [JWFriendCell cellWithTableView:tableView]; 47 cell.friendDatas = [self.friendGroup[indexPath.section] friends][indexPath.row]; 48 return cell; 49 } 50 #pragma mark - JWFriendHeaderView的方法 51 //显示组头view的内容 52 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 53 JWFriendHeaderView *headerView = [JWFriendHeaderView headerViewWithTableView:tableView]; 54 headerView.friendGroup = self.friendGroup[section]; 55 headerView.delegate = self; 56 headerView.tag = section;//把section赋值给组头的tag 57 return headerView; 58 } 59 #pragma mark - JWFriendHeaderViewDelegate的方法 60 - (void)clickNameBtn:(JWFriendHeaderView *)headerView { 61 NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:headerView.tag]; 62 [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone];//判断点击的是哪个组头,然后加载对应的数据 63 } 64 @end