iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)
一、实现效果
二、实现代码
1.数据模型部分
YYQQGroupModel.h文件
// // YYQQGroupModel.h // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import <Foundation/Foundation.h> @interface YYQQGroupModel : NSObject /** * 名称属性 */ @property(nonatomic,copy)NSString *name; /** * 是否在线 */ @property(nonatomic,copy)NSString *online; /** * 好友列表 */ @property(nonatomic,strong)NSArray *friends; //记录当前组是否要打开 @property(nonatomic,assign,getter = isOpen)BOOL open; -(instancetype)initWithDict:(NSDictionary *)dict; +(instancetype) qqGroupModelWithDict:(NSDictionary *)dict; @end
YYQQGroupModel.m文件
// // YYQQGroupModel.m // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYQQGroupModel.h" #import "YYFriendsModel.h" @implementation YYQQGroupModel -(instancetype)initWithDict:(NSDictionary *)dict { if (self=[super init]) { //将字典转换为模型 [self setValuesForKeysWithDictionary:dict]; //定义一个数组来保存转换后的模型 NSMutableArray *models=[NSMutableArray arrayWithCapacity:self.friends.count]; for (NSDictionary *dict in self.friends) { YYFriendsModel *friends=[YYFriendsModel friendsWithDict:dict]; [models addObject:friends]; } _friends=[models copy]; } return self; } +(instancetype)qqGroupModelWithDict:(NSDictionary *)dict { return [[self alloc]initWithDict:dict]; } @end
YYFriendsModel.h文件
// // YYFriendsModel.h // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import <Foundation/Foundation.h> @interface YYFriendsModel : NSObject /** * 每个好友的名称 */ @property(nonatomic,copy)NSString *name; /** *每个好友的头像 */ @property(nonatomic,copy)NSString *icon; /** * 每个好友的个性签名 */ @property(nonatomic,copy)NSString *intro; /** * 该好友是否是vip */ @property(nonatomic,assign,getter = isVip)BOOL vip; -(instancetype)initWithDict:(NSDictionary *)dict; +(instancetype)friendsWithDict:(NSDictionary *)dict; @end
YYFriendsModel.m文件
// // YYFriendsModel.m // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYFriendsModel.h" @implementation YYFriendsModel -(instancetype)initWithDict:(NSDictionary *)dict { if (self=[super init]) { [self setValuesForKeysWithDictionary:dict]; } return self; } +(instancetype)friendsWithDict:(NSDictionary *)dict { return [[self alloc]initWithDict:dict]; } @end
2.视图部分
YYfriendCell.h文件
// // YYfriendCell.h // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import <UIKit/UIKit.h> @class YYFriendsModel; @interface YYfriendCell : UITableViewCell @property(nonatomic,strong)YYFriendsModel *friends; +(instancetype)cellWithTableview:(UITableView *)tableView; @end
YYfriendCell.m文件
// // YYfriendCell.m // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYfriendCell.h" #import "YYFriendsModel.h" //私有扩展 @interface YYfriendCell() @end @implementation YYfriendCell +(YYfriendCell *)cellWithTableview:(UITableView *)tableView { static NSString *identifier=@"qq"; YYfriendCell *cell=[tableView dequeueReusableCellWithIdentifier:identifier]; if (cell==nil) { //这里使用系统自带的样式 cell=[[YYfriendCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; NSLog(@"创建一个cell"); } return cell; } -(void)setFriends:(YYFriendsModel *)friends { _friends=friends; //1.设置头像 self.imageView.image=[UIImage imageNamed:_friends.icon]; //2.设置昵称 self.textLabel.text=_friends.name; //3.设置简介 self.detailTextLabel.text=_friends.intro; //判断是否是会员 /** * 这里有个注意点,如果不写else设置为黑色,会怎么样? */ if (_friends.isVip) { [self.textLabel setTextColor:[UIColor redColor]]; }else { [self.textLabel setTextColor:[UIColor blackColor]]; } //调整字体的大小 self.textLabel.font=[UIFont systemFontOfSize:15.f]; self.detailTextLabel.font=[UIFont systemFontOfSize:10.f]; } @end
YYHeaderView.h文件
// // YYHeaderView.h // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-6-1. // Copyright (c) 2014年 itcase. All rights reserved. // #import <UIKit/UIKit.h> @class YYQQGroupModel,YYHeaderView; //商量一个协议 @protocol YYHeaderViewDelegate <NSObject> -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView; @end @interface YYHeaderView : UITableViewHeaderFooterView @property(nonatomic,strong)YYQQGroupModel *group; //提供一个类方法,创建一个头部视图 +(instancetype)headerWithTableView:(UITableView *)tableView; //delegate遵守YYHeaderViewDelegate这个协议,可以使用协议中的方法 @property(nonatomic,weak)id<YYHeaderViewDelegate> delegate; @end
YYHeaderView.m文件
// // YYHeaderView.m // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-6-1. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYHeaderView.h" #import "YYQQGroupModel.h" @interface YYHeaderView() @property(nonatomic,strong)UIButton *btn; @property(nonatomic,strong)UILabel *lab; @end @implementation YYHeaderView //创建一个自定义的头部分组视图 +(instancetype)headerWithTableView:(UITableView *)tableView { static NSString *indentifier=@"header"; //先到缓存池中去取数据 YYHeaderView *headerview=[tableView dequeueReusableCellWithIdentifier:indentifier]; //如果没有,则自己创建 if (headerview==nil) { headerview=[[YYHeaderView alloc]initWithReuseIdentifier:indentifier]; } //返回一个头部视图 return headerview; } #warning 注意在构造方法中为控件设置的frame是无效的 -(id)initWithReuseIdentifier:(NSString *)reuseIdentifier { //初始化父类中的构造方法 if (self=[super initWithReuseIdentifier:reuseIdentifier]) { //创建一个按钮 UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom]; //设置按钮的属性 //设置普通状态下按钮的背景图片 [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal]; //设置高亮状态下按钮的背景图片 [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted]; //设置按钮上的小三角图片 [btn setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal]; //设置按钮上信息的对其方式为左对齐 btn.contentHorizontalAlignment=UIControlContentHorizontalAlignmentLeft; //设置小三角图片的内边距 btn.contentEdgeInsets=UIEdgeInsetsMake(0, 20, 0, 0); //设置按钮上文字距离小三角图片的距离 btn.titleEdgeInsets=UIEdgeInsetsMake(0, 20, 0, 0); //设置按钮上分组标题的文本颜色(默认是白色) //[btn setTintColor:[UIColor blackColor]]; [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; //添加按钮的点击事件 [btn addTarget:self action:@selector(btnOnclick:) forControlEvents:UIControlEventTouchUpInside]; // 设置btn中的图片不填充整个imageview btn.imageView.contentMode = UIViewContentModeCenter; // 超出范围的图片不要剪切 // btn.imageView.clipsToBounds = NO; btn.imageView.layer.masksToBounds = NO; //把按钮添加到视图 [self addSubview:btn]; self.btn=btn; //创建一个lab UILabel *lab=[[UILabel alloc]init]; //设置在线人数的对齐方式为右对齐 lab.textAlignment=NSTextAlignmentRight; //设置在线人数的文本颜色为灰色 lab.textColor=[UIColor grayColor]; [self addSubview:lab]; self.lab=lab; } return self; } -(void)btnOnclick:(UIButton *)btn { NSLog(@"按钮被点击了"); //修改模型的isopen属性 //1.修改模型数据 self.group.open=!self.group.isOpen; //2.刷新表格 //(刷新表格的功能由控制器完成,在这里可以设置一个代理),当按钮被点击的时候,就通知代理对表格进行刷新 //通知代理 if ([self.delegate respondsToSelector:@selector(headerViewDidClickHeaderView:)]) { [self.delegate headerViewDidClickHeaderView:self]; } } //当控件的frame值改变时,会自动调用该方法,故可以在该方法中设置控件的frame; -(void)layoutSubviews { #warning 一定不要忘记调用父类的方法 [super layoutSubviews]; //设置按钮的frame和头部视图一样大小 self.btn.frame=self.bounds; //设置lab的frame CGFloat padding=20; CGFloat labW=50; CGFloat labH=self.frame.size.height; CGFloat labY=0; CGFloat labX=self.frame.size.width-padding-labW; self.lab.frame=CGRectMake(labX, labY, labW, labH); } #pragma mark - 当一个控件被添加到其它视图上的时候会调用以下方法 // 已经被添加到父视图上的时候会调用 - (void)didMoveToSuperview { NSLog(@"已经添加到视图了"); // 在这个方法中就快要拿到最新的被添加到tableview上的头部视图修改它的图片 if (self.group.isOpen) { //让小三角图片向下旋转 self.btn.imageView.transform = CGAffineTransformMakeRotation(M_PI_2); } } // 即将被添加到父视图上的时候会调用 - (void)willMoveToSuperview:(UIView *)newSuperview { NSLog(@"将要添加到视图了"); } //重写get方法,设置数据 -(void)setGroup:(YYQQGroupModel *)group { _group=group; //设置分组标题 //self.btn.titleLabel.text=_group.name; #warning 请注意在设置按钮的文本时,一定要设置按钮的状态,像上面这样设置不会显示 [self.btn setTitle:_group.name forState:UIControlStateNormal]; NSLog(@"%@",self.btn.titleLabel.text); //设置在线人数 self.lab.text=[NSString stringWithFormat:@"%@/%d",_group.online,_group.friends.count]; } @end
3.控制器部分
YYViewController.h文件
// // YYViewController.h // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import <UIKit/UIKit.h> @interface YYViewController : UITableViewController @end
YYViewController.m文件
// // YYViewController.m // 02-QQ好友列表(基本数据的加载) // // Created by apple on 14-5-31. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYViewController.h" #import "YYQQGroupModel.h" #import "YYfriendCell.h" #import "YYFriendsModel.h" #import "YYHeaderView.h" @interface YYViewController ()<YYHeaderViewDelegate> /** * 用来保存所有的分组数据 */ @property(nonatomic,strong)NSArray *groupFriends; @end @implementation YYViewController #pragma mark-懒加载 //1.先拿到数据,实现懒加载 -(NSArray *)groupFriends { if (_groupFriends==nil) { NSString *fullpath=[[NSBundle mainBundle]pathForResource:@"friends.plist" ofType:nil]; NSArray *arrayM=[NSArray arrayWithContentsOfFile:fullpath]; NSMutableArray *models=[NSMutableArray arrayWithCapacity:arrayM.count]; for (NSDictionary *dict in arrayM) { YYQQGroupModel *group=[YYQQGroupModel qqGroupModelWithDict:dict]; [models addObject:group]; } _groupFriends=[models copy]; } return _groupFriends; } - (void)viewDidLoad { [super viewDidLoad]; self.tableView.sectionHeaderHeight = 100; } #pragma mark- 设置数据源 //返回多少组 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.groupFriends.count; } //每组返回多少行 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // //取出对应的组模型 YYQQGroupModel *group=self.groupFriends[section]; // //返回对应组中的好友数 // return group.friends.count; //在这里进行判断,如果该组收拢,那就返回0行,如果该组打开,就返回实际的行数 // if (group.isOpen) { // return group.friends.count; // }else // { // return 0; // } if (group.isOpen) { // 代表要展开 return group.friends.count; }else { // 代表要合拢 return 0; } } //每组每行的内容 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //1.创建cell YYfriendCell *cell=[YYfriendCell cellWithTableview:tableView]; //2.设置cell YYQQGroupModel *group=self.groupFriends[indexPath.section]; YYFriendsModel *friends=group.friends[indexPath.row]; cell.friends=friends; //3.返回一个cell return cell; } #pragma mark - 代理方法 // 当一个分组标题进入视野的时候就会调用该方法 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // // 1.创建头部视图 // UIView *view = [[UIView alloc] init]; // view.backgroundColor = [UIColor grayColor]; // // 2.返回头部视图 // return view; //创建自定义的头部视图 YYHeaderView *headerview=[YYHeaderView headerWithTableView:tableView]; //设置当前控制器为代理 headerview.delegate=self; //设置头部视图的数据 YYQQGroupModel *groupmodel=self.groupFriends[section]; headerview.group=groupmodel; //返回头部视图 return headerview; } #pragma mark - YYHeaderViewDelegate -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView { //重新调用数据源的方法刷新数据 [self.tableView reloadData]; } //设置分组头部标题的高度 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 30; } #pragma mark 隐藏状态栏 -(BOOL)prefersStatusBarHidden { return YES; } @end
三、代码说明
1.项目文件结构
2.注意点
(1)调整字体的大小: self.textLabel.font=[UIFont systemFontOfSize:15.f];
(2)-(void)layoutSubviews方法。该方法在控件的frame被改变的时候就会调用,这个方法一般用于调整子控件的位置,注意一定要调用[super layoutSubviews];
(3)但凡在init方法中获取到的frame都是0;
(4)如果控件不显示,有以下一些排错方法
(5)请注意在设置按钮的文本时,一定要设置按钮的状态
(6)调用构造方法时,一定要先初始化父类的方法,先判断,再进行自己属性的初始化
1) 已经被添加到父视图上的时候会调用- (void)didMoveToSuperview
2) 即将被添加到父视图上的时候会调用- (void)willMoveToSuperview:(UIView *)newSuperview
(8)图片填充知识
1)设置btn中的图片不填充整个imageview btn.imageView.contentMode = UIViewContentModeCenter;
2)超出范围的图片不要剪切
//btn.imageView.clipsToBounds = NO;
btn.imageView.layer.masksToBounds = NO;
四、补充(代理)
@protocol YYHeaderViewDelegate <NSObject>
-(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView;
@end
//delegate遵守YYHeaderViewDelegate这个协议,可以使用协议中的方法
@property(nonatomic,weak)id<YYHeaderViewDelegate> delegate;
@interface YYViewController ()<YYHeaderViewDelegate>
-(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView
{
[self.tableView reloadData];
}
headerview.delegate=self;