1.实现效果
2.关键点:每个分组的展开和折叠,主要是对每组的行数进行设置,展开为count,折叠为0
3.思想思路:先实现数据模型逻辑-->展示基本数据-->自定义cell-->自定义cellHeaderView视图-->在cellHeaderView中设置协议,controller中遵守协议,实现cellHeaderView点击事件的传递(即好友列表折叠点击事件的实现)
4.主要代码
1)friend ,group数据模型的定义
1 // 2 // FriendModel.h 3 // 1.自定义cell(纯代码) 4 // 5 // Created by 许霞 on 16/9/7. 6 // Copyright © 2016年 jmchat. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface FriendModel : NSObject 12 /** 13 * 图片 14 */ 15 @property (nonatomic,copy) NSString *icon; 16 /** 17 * 介绍 18 */ 19 @property (nonatomic,copy) NSString *intro; 20 /** 21 * 姓名 22 */ 23 @property (nonatomic,copy) NSString *name; 24 /** 25 * 是否是vip 26 */ 27 @property (nonatomic,assign,getter=isVip) BOOL vip; 28 29 - (instancetype)initWithDict:(NSDictionary *)dict; 30 + (instancetype)friendModelWithDict:(NSDictionary *)dict; 31 @end
// // FriendModel.m // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import "FriendModel.h" @implementation FriendModel - (instancetype)initWithDict:(NSDictionary *)dict { if (self =[super init]) { [self setValuesForKeysWithDictionary:dict]; } return self; } + (instancetype)friendModelWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } @end
// // GroupModel.h // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import <Foundation/Foundation.h> @interface GroupModel : NSObject /** * 姓名 */ @property (nonatomic,copy) NSString *name; /** * 在线数 */ @property (nonatomic,assign) int online; /** * 朋友 */ @property (nonatomic,strong) NSArray *friends; /** * 是否展开 */ @property (nonatomic,assign,getter=isOpened) BOOL opened; + (instancetype)groupModelWithDict:(NSDictionary *)dict; - (instancetype)initWithDict:(NSDictionary *)dict; @end
// // GroupModel.m // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import "GroupModel.h" #import "FriendModel.h" @implementation GroupModel + (instancetype)groupModelWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict { if (self =[super init]) { [self setValuesForKeysWithDictionary:dict]; } NSMutableArray * friendArray =[NSMutableArray array]; for (NSDictionary * friendDict in _friends) { FriendModel * friend =[FriendModel friendModelWithDict:friendDict]; [friendArray addObject:friend]; } _friends = friendArray; return self; } @end
2)cell,headerView的定义
// // FriendTableViewCell.h // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import <UIKit/UIKit.h> @class FriendModel; @interface FriendTableViewCell : UITableViewCell @property (nonatomic,strong) FriendModel * friendData; +(instancetype) cellWithTableView:(UITableView *)tableView; @end
// // FriendTableViewCell.m // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import "FriendTableViewCell.h" #import "FriendModel.h" @implementation FriendTableViewCell +(instancetype)cellWithTableView:(UITableView *)tableView { static NSString *ID = @"friend"; FriendTableViewCell * cell =[tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[FriendTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell; } - (void)setFriendData:(FriendModel *)friendData { _friendData = friendData; self.textLabel.text =_friendData.name; self.detailTextLabel.text = _friendData.intro; self.imageView.image =[UIImage imageNamed:_friendData.icon]; self.textLabel.textColor = _friendData.isVip?[UIColor redColor]:[UIColor blackColor]; } @end
// // GroupHeaderView.h // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import <UIKit/UIKit.h> @class GroupModel,GroupHeaderView; @protocol GroupHeaderViewDelegate <NSObject> @optional - (void)headerViewDidClickedNameView:(GroupHeaderView *)headerView; @end @interface GroupHeaderView : UITableViewHeaderFooterView @property (nonatomic, strong) GroupModel * group; @property (nonatomic, weak) id <GroupHeaderViewDelegate> delegate; +(instancetype)headerViewWithTableView:(UITableView *)tableView; - (void)updateHeaderView; @end
// // GroupHeaderView.m // 1.自定义cell(纯代码) // // Created by 许霞 on 16/9/7. // Copyright © 2016年 jmchat. All rights reserved. // #import "GroupHeaderView.h" #import "GroupModel.h" @interface GroupHeaderView () @property (nonatomic,weak) UILabel * countView; @property (nonatomic,weak) UIButton *nameView; @end @implementation GroupHeaderView +(instancetype)headerViewWithTableView:(UITableView *)tableView; { static NSString *ID =@"groupHeader"; GroupHeaderView * header =[tableView dequeueReusableHeaderFooterViewWithIdentifier:ID]; if (header == nil) { header =[[GroupHeaderView alloc] initWithReuseIdentifier:ID]; } return header; } - (id) initWithReuseIdentifier:(NSString *)reuseIdentifier { if (self =[super initWithReuseIdentifier:reuseIdentifier]) { //1.添加子控件 UIButton * nameView =[UIButton buttonWithType:UIButtonTypeCustom]; [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal]; [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted]; [nameView setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal]; [nameView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; nameView.titleEdgeInsets =UIEdgeInsetsMake(0, 10, 0, 0); nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0); nameView.imageView.contentMode = UIViewContentModeCenter; nameView.imageView.clipsToBounds = NO; [nameView addTarget:self action:@selector(nameViewClick) forControlEvents:UIControlEventTouchUpInside]; [self.contentView addSubview:nameView]; self.nameView = nameView; UILabel *countView =[[UILabel alloc] init]; countView.textAlignment = NSTextAlignmentRight; countView.textColor = [UIColor grayColor]; [self.contentView addSubview:countView]; self.countView = countView; } return self; } - (void)layoutSubviews { [super layoutSubviews]; self.nameView.frame = self.bounds; CGFloat countY = 0; CGFloat countH =self.nameView.frame.size.height; CGFloat countW = 150; CGFloat countX = self.frame.size.width-10-countW; self.countView.frame = CGRectMake(countX, countY, countW, countH); } -(void)setGroup:(GroupModel *)group { _group = group; [self.nameView setTitle:group.name forState:UIControlStateNormal]; self.countView.text =[NSString stringWithFormat:@"%d/%u",group.online,group.friends.count]; } - (void)nameViewClick { self.group.opened = !self.group.opened; if ([self.delegate respondsToSelector:@selector(headerViewDidClickedNameView:)]) { [self.delegate headerViewDidClickedNameView:self]; } } - (void)updateHeaderView { if (self.group.opened) { self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2); }else{ self.nameView.imageView.transform = CGAffineTransformMakeRotation(0); } } //- (void)willMoveToSuperview:(UIView *)newSuperview //{ // if (self.group.opened) { // self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2); // }else{ // self.nameView.imageView.transform = CGAffineTransformMakeRotation(0); // } //} @end
3)controller的实现
1 // 2 // ViewController.m 4 // 5 // Created by 许霞 on 16/9/7. 6 // Copyright © 2016年 jmchat. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "GroupModel.h" 11 #import "FriendModel.h" 12 #import "FriendTableViewCell.h" 13 #import "GroupHeaderView.h" 14 15 @interface ViewController ()<UITableViewDataSource,UITableViewDelegate,GroupHeaderViewDelegate> 16 @property (nonatomic,strong) UITableView * tableView; 17 @property (nonatomic,strong) NSArray * dataArray; 18 @end 19 20 @implementation ViewController 21 22 - (void)viewDidLoad { 23 [super viewDidLoad]; 24 [self initUI]; 25 } 26 /** 27 * 懒加载实现数据的加载 28 */ 29 30 - (NSArray *)dataArray 31 { 32 if (_dataArray ==nil) { 33 NSArray * dictArray =[[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil] ]; 34 NSMutableArray *groups =[NSMutableArray array]; 35 for (NSDictionary * groupDict in dictArray) { 36 GroupModel * group =[GroupModel groupModelWithDict:groupDict]; 37 [groups addObject:group]; 38 } 39 _dataArray = groups; 40 } 41 return _dataArray; 42 } 43 44 - (void) initUI 45 { 46 self.tableView.autoresizesSubviews = NO; 47 self.tableView =[[UITableView alloc] initWithFrame:CGRectMake(0, 20, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) style:UITableViewStylePlain]; 48 _tableView.delegate =self; 49 _tableView.dataSource =self; 50 _tableView.rowHeight = 50.0f; 51 _tableView.sectionHeaderHeight = 44.0f; 52 [self.view addSubview:_tableView]; 53 } 54 #pragma mark- 55 #pragma mark-UITableViewDataSource 56 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 57 { 58 return self.dataArray.count; 59 } 60 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 61 { 62 GroupModel * group = self.dataArray[section]; 63 return group.opened? group.friends.count:0; 64 } 65 66 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 67 { 68 //1.创建cell 69 FriendTableViewCell * cell =[FriendTableViewCell cellWithTableView:tableView]; 70 //2.设置cell数据 71 GroupModel * group =self.dataArray[indexPath.section]; 72 FriendModel * friendData = group.friends[indexPath.row]; 73 cell.friendData = friendData; 74 75 76 return cell; 77 } 78 79 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 80 { 81 return 30.0f; 82 } 83 84 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 85 { 86 //1.创建头部控件 87 GroupHeaderView * headerView =[GroupHeaderView headerViewWithTableView:tableView]; 88 headerView.delegate =self; 89 //2.给Header设置数据(传递模型给header) 90 headerView.group =self.dataArray[section]; 91 [headerView updateHeaderView]; 92 93 return headerView; 94 } 95 96 #pragma mark- 97 #pragma mark --GroupHeaderViewDelegate 98 - (void)headerViewDidClickedNameView:(GroupHeaderView *)headerView 99 { 100 [self.tableView reloadData]; 101 } 102 103 104 @end
5.经验总结
1)隐藏显示状态栏方法
-(BOOL)prefersStatusBarHidden
{
return YES;
}
2)friend 是c++关键字,不能用friend作为属性名
3)当一个控件被添加到父控件的中就会调用
- (void)didMoveToSuperView
{
}
4)headerView和cell一样,都有一个复用机制,但是当刷新tableVIew的时候,是不会从缓存池中取的,而是重新创建
5)layoutSubviews (一般在这里布局内部的子控件,设置子控件的frame,当一个控件的frame发生改变的时候就会调用)
6)tableView 的类型如果是plain可以实现组头固定显示;如果是group则无此效果,且如果为plain类型, 设置其组头,组为的高度为0有效,而group类型则无效,但可以设置为0.000001等极小数,可以实现组头,组尾视图的高度设置;
7)将数据源数组设置为不可变,是保证数据安全,不会被合作程序员不小心修改,也是让合作者透露,此数据源数组,不能更改
8)懒加载是写在get方法,如果你需要的时候,才会创建,而if(_group==nil),这里一定不能使用self.group,这样会导致循环调用
9)当模型中又包含有其他模型时,我们需要对其模型部分进行处理,大致思路仍是:用kvc实现复制,但是包含模型部分的数据,被kvc设置为了普通数据,我们单独对此部分进行重新设置即可,关键代码如下:
-(instancetype)initWithDict:(NSDictionary *)dict { if (self =[super init]){ //1.注入所有属性 [self setValuesForKeysWithDictionary:dict]; //2.特殊处理friends属性 NSMutabelArray *friendArray =[NSMutableArray array]; for (NSDictionary *dict in self.friends) { Friend * friend =[Friend friendWithDict:dict]; [friendArray addObject:friend]; } self.friends = friendArray; } return self; }
10)代码仓库不确定的<#type#>进行设置
11)BOOL值属性,我们一般通过,getter关键字对其重命名
@property (nonatomic,assign,getter = isVip) BOOL vip
12)如果某个控件不出来,可以考虑的原因如下:
1.frame的尺寸和位置对不对; 2.hidden是否为YES; 3.有没有添加到父控件中; 4.alpha 是否 < 0.01; 5.被其他控件挡住了 ;6.父控件的前面5个情况.
13)按钮的一些属性:
1.设置按钮的内容的对齐方式:(垂直方向上:上下对齐;水平方向上:左右对齐)
nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
2.设置按钮的图片,文字,整体内容的内边距(这里内边距对象格式为:上左下右,逆时针方向设置)
nameView.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
3.设置按钮的内容,文字,图片的显示模式
nameView.imageView.contentMode = UIViewContentModeCenter;
4.设置按钮图片超过边框的内容是否裁剪
nameView.imageView.clipsToBounds = NO;