一.项目前准备
1.pch文件如下
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#import
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import
#import
#endif
2.friends.plist文件如下
3.根控制器设置为MJTableViewController
二.使用MVC开发模式
1.模型文件分别是朋友模型和组模型
①.朋友模型:
// MJFriend.h
#import
@interface MJFriend : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *intro;
@property (nonatomic, assign, getter = isVip) BOOL vip;
+ (instancetype)friendWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
// MJFriend.m
#import "MJFriend.h"
@implementation MJFriend
+ (instancetype)friendWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
②.组模型:
// MJFriendGroup.h
#import
@interface MJFriendGroup : NSObject
@property (nonatomic, copy) NSString *name;
/**
* 数组中装的都是MJFriend模型
*/
@property (nonatomic, strong) NSArray *friends;
@property (nonatomic, assign) int online;
/**
* 标识这组是否需要展开, YES : 展开 , NO : 关闭
*/
@property (nonatomic, assign, getter = isOpened) BOOL opened;
+ (instancetype)groupWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
// MJFriendGroup.m
#import "MJFriendGroup.h"
#import "MJFriend.h"
@implementation MJFriendGroup
+ (instancetype)groupWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
//将friends的数据存起来
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
// 1.注入所有属性
[self setValuesForKeysWithDictionary:dict];
// 2.特殊处理friends属性
NSMutableArray *friendArray = [NSMutableArray array];
for (NSDictionary *dict in self.friends) {
MJFriend *friend = [MJFriend friendWithDict:dict];
[friendArray addObject:friend];
}
self.friends = friendArray;
}
return self;
}
@end
①.cell代码
// MJFriendCell.h
#import
@class MJFriend;
@interface MJFriendCell : UITableViewCell
+ (instancetype)cellWithTableView:(UITableView *)tableView;
// friend是C++的关键字,不能用friend作为属性名
@property (nonatomic, strong) MJFriend *friendData;
@end
// MJFriendCell.m
#import "MJFriendCell.h"
#import "MJFriend.h"
@implementation MJFriendCell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"friend";
MJFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[MJFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
return cell;
}
- (void)setFriendData:(MJFriend *)friendData
{
_friendData = friendData;
self.imageView.image = [UIImage imageNamed:friendData.icon];
self.textLabel.text = friendData.name;
self.textLabel.textColor = friendData.isVip ? [UIColor redColor] : [UIColor blackColor];
self.detailTextLabel.text = friendData.intro;
}
@end
②.组视图代码
// MJHeaderView.h
#import
@class MJFriendGroup, MJHeaderView;
//点击了头视图,传递给控制器
@protocol MJHeaderViewDelegate
@optional
- (void)headerViewDidClickedNameView:(MJHeaderView *)headerView;
@end
@interface MJHeaderView : UITableViewHeaderFooterView
+ (instancetype)headerViewWithTableView:(UITableView *)tableView;
@property (nonatomic, strong) MJFriendGroup *group;
@property (nonatomic, weak) id delegate;
@end
// MJHeaderView.m
#import "MJHeaderView.h"
#import "MJFriendGroup.h"
/**
某个控件出不来:
1.frame的尺寸和位置对不对
2.hidden是否为YES
3.有没有添加到父控件中
4.alpha 是否 < 0.01
5.被其他控件挡住了
6.父控件的前面5个情况
*/
@interface MJHeaderView()
@property (nonatomic, weak) UILabel *countView;
@property (nonatomic, weak) UIButton *nameView;
@end
@implementation MJHeaderView
+ (instancetype)headerViewWithTableView:(UITableView *)tableView
{
static NSString *ID = @"header";
MJHeaderView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
if (header == nil) {
header = [[MJHeaderView alloc] initWithReuseIdentifier:ID];
}
return header;
}
/**
* 在这个初始化方法中,MJHeaderView的frame\bounds没有值
*/
- (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.imageEdgeInsets
nameView.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
[nameView addTarget:self action:@selector(nameViewClick) forControlEvents:UIControlEventTouchUpInside];
// 设置按钮内部的imageView的内容模式为居中
nameView.imageView.contentMode = UIViewContentModeCenter;
// 超出边框的内容不需要裁剪
nameView.imageView.clipsToBounds = NO;
[self.contentView addSubview:nameView];
self.nameView = nameView;
// 2.添加好友数
UILabel *countView = [[UILabel alloc] init];
countView.textAlignment = NSTextAlignmentRight;
countView.textColor = [UIColor grayColor];
[self.contentView addSubview:countView];
self.countView = countView;
}
return self;
}
/**
* 当一个控件的frame发生改变的时候就会调用
*
* 一般在这里布局内部的子控件(设置子控件的frame)
*/
- (void)layoutSubviews
{
#warning 一定要调用super的方法
[super layoutSubviews];
// 1.设置按钮的frame
self.nameView.frame = self.bounds;
// 2.设置好友数的frame
CGFloat countY = 0;
CGFloat countH = self.frame.size.height;
CGFloat countW = 150;
CGFloat countX = self.frame.size.width - 10 - countW;
self.countView.frame = CGRectMake(countX, countY, countW, countH);
}
- (void)setGroup:(MJFriendGroup *)group
{
_group = group;
// 1.设置按钮文字(组名)
[self.nameView setTitle:group.name forState:UIControlStateNormal];
// 2.设置好友数(在线数/总数)
self.countView.text = [NSString stringWithFormat:@"%d/%d", group.online, group.friends.count];
}
/**
* 监听组名按钮的点击
*/
- (void)nameViewClick
{
// 1.修改组模型的标记(状态取反)
self.group.opened = !self.group.isOpened;
// 2.刷新表格 点击那个头视图就把谁传过去
if ([self.delegate respondsToSelector:@selector(headerViewDidClickedNameView:)]) {
[self.delegate headerViewDidClickedNameView:self];
}
}
/**
* 当一个控件被添加到父控件中就会调用,如果把这个方法里面的代码写在nameViewClick里面,这样点击按钮的时候控制器就会刷新cell,就会从缓存池里面取出新的headview,这样我们的旋转就没用了,所以我们把旋转的处理写在这个方法里面
*/
- (void)didMoveToSuperview
{
if (self.group.opened) {
self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
} else {
self.nameView.imageView.transform = CGAffineTransformMakeRotation(0);
}
}
/**
* 当一个控件即将被添加到父控件中会调用
*/
//- (void)willMoveToSuperview:(UIView *)newSuperview
//{
//
//}
@end
.h文件
// MJViewController.h
#import
@interface MJViewController : UITableViewController
@end
.m文件
// MJViewController.m
#import "MJViewController.h"
#import "MJFriendGroup.h"
#import "MJFriend.h"
#import "MJHeaderView.h"
#import "MJFriendCell.h"
@interface MJViewController ()
@property (nonatomic, strong) NSArray *groups;
@end
@implementation MJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 每一行cell的高度
self.tableView.rowHeight = 50;
// 每一组头部控件的高度
self.tableView.sectionHeaderHeight = 44;
}
- (NSArray *)groups
{
if (_groups == nil) {
NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil]];
NSMutableArray *groupArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
MJFriendGroup *group = [MJFriendGroup groupWithDict:dict];
[groupArray addObject:group];
}
_groups = groupArray;
}
return _groups;
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
#pragma mark - 数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.groups.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
MJFriendGroup *group = self.groups[section];
return (group.isOpened ? group.friends.count : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.创建cell
MJFriendCell *cell = [MJFriendCell cellWithTableView:tableView];
// 2.设置cell的数据
MJFriendGroup *group = self.groups[indexPath.section];
cell.friendData = group.friends[indexPath.row];
return cell;
}
/**
* 返回每一组需要显示的头部标题(字符出纳)
*/
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// 1.创建头部控件
MJHeaderView *header = [MJHeaderView headerViewWithTableView:tableView];
header.delegate = self;
// 2.给header设置数据(给header传递模型)
header.group = self.groups[section];
return header;
}
#pragma mark - headerView的代理方法
/**
* 点击了headerView上面的名字按钮时就会调用, 重新刷新cell
*/
- (void)headerViewDidClickedNameView:(MJHeaderView *)headerView
{
[self.tableView reloadData];
}
@end