ios-day09-02(QQ好友列表。自定义UITableViewHeaderFooterView、如何控制UITableView每一组的展开和闭合、代理的使用)

源码下载地址:http://download.csdn.net/detail/liu537192/8478745


效果图:



核心代码:

//
//  JLViewController.m
//  02-QQ好友列表
//
//  Created by XinYou on 15-3-6.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLViewController.h"
#import "JLFriend.h"
#import "JLFriendGroup.h"
#import "JLHeaderView.h"
#import "JLFriendCell.h"

@interface JLViewController () 
    
    
     
     

@property (nonatomic,strong)NSArray *groups;

@end

@implementation JLViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 设置tableView的行高
    self.tableView.rowHeight = 50;
    
    // 设置tableView每一组headerView的高度
    self.tableView.sectionHeaderHeight = 44;
    
}

/**
 *  隐藏状态栏
 */
- (BOOL)prefersStatusBarHidden{

    return YES;
}

- (NSArray *)groups{

    if (_groups == nil) {
        // 获取plist文件的路径
        NSString *path = [[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil];
        
        // 加载plist文件中的内容到数组
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
        
        NSMutableArray *tempArray = [NSMutableArray array];
        
        for (NSDictionary *dict in dictArray) {
            JLFriendGroup *group = [JLFriendGroup groupWithDict:dict];
            
            [tempArray addObject:group];
        }
        
        _groups = tempArray;
    }

    return _groups;
}

#pragma mark -JLHeaderViewDelegate的方法
- (void)headerViewDidClickNameView:(JLHeaderView *)headerView{
    
    // 重新加载数据,刷新表格
    [self.tableView reloadData];
}

#pragma mark -数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

    return self.groups.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    JLFriendGroup *group = self.groups[section];
    
//    return group.friends.count;
    // 控制每组的展开和闭合
    return (group.isOpened == NO ? 0 :group.friends.count);
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

//    static NSString *ID = @"qq";
//    
//    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
//    
//    if (cell == nil) {
//        
//        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
//        
//    }
//    
//    JLFriendGroup *group = self.groups[indexPath.section];
//    JLFriend *friend = group.friends[indexPath.row];
//    
//    cell.imageView.image = [UIImage imageNamed:friend.icon];
//    cell.textLabel.text = friend.name;
//    // vip红色昵称
//    cell.textLabel.textColor = (friend.isVip ? [UIColor redColor] : [UIColor blackColor]);
//    cell.detailTextLabel.text = friend.intro;
    
    // 将以上创建cell的代码封装起来,变成如下代码:
    
    JLFriendGroup *group = self.groups[indexPath.section];
    JLFriend *friend = group.friends[indexPath.row];
    
    // 创建cell
    JLFriendCell *cell = [JLFriendCell cellWithTableView:tableView];
    
    // 给cell设置数据
    cell.friendData = friend;
    
    return cell;
}

// 使用系统自带的headerView,不能满足条件
//- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//
//    JLFriendGroup *group = self.groups[section];
//    return group.name;
//}

#pragma mark -代理方法
/**
 *  使用自定义的headerView
 */
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    // 创建headerView
    JLHeaderView *headerView= [JLHeaderView headViewWithTableView:tableView];
    
    // 给headerView设置数据
    headerView.group = self.groups[section];
    
    headerView.delegate = self;
    
    return headerView;
}

@end

    
    
//
//  JLFriend.h
//  02-QQ好友列表
//
//  Created by XinYou on 15-3-6.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
    
    
     
     

@interface JLFriend : 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)friendWithDict:(NSDictionary *)dict;

@end
//
//  JLFriend.m
//  02-QQ好友列表
//
//  Created by XinYou on 15-3-6.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLFriend.h"

@implementation JLFriend

- (instancetype)initWithDict:(NSDictionary *)dict{

    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    
    return self;
}

+ (instancetype)friendWithDict:(NSDictionary *)dict{

    return [[self alloc] initWithDict:dict];
}

@end
//
//  JLFriendGroup.h
//  02-QQ好友列表
//
//  Created by XinYou on 15-3-6.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
     
     
      
      

@interface JLFriendGroup : NSObject
/**
 *  组名
 */
@property (nonatomic,copy) NSString *name;
/**
 *  数组中的元素都是JLFriend模型
 */
@property (nonatomic,strong)NSArray *friends;
/**
 *  某一组的当前在线人数
 */
@property (nonatomic,assign) int online;
/**
 *  标记这组是否需要打开。YES表示打开,NO表示不打开
 */
@property (nonatomic,assign,getter = isOpened) BOOL opened;

- (instancetype)initWithDict:(NSDictionary *)dict;

+ (instancetype)groupWithDict:(NSDictionary *)dict;

@end
//
//  JLFriendGroup.m
//  02-QQ好友列表
//
//  Created by XinYou on 15-3-6.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import "JLFriendGroup.h"
#import "JLFriend.h"

@implementation JLFriendGroup

- (instancetype)initWithDict:(NSDictionary *)dict{

    if (self = [super init]) {
        // KVC 
        [self setValuesForKeysWithDictionary:dict];
        // 经过KVC处理后,friends数组中装得都是NSDictionary对象
        // 而我们需要friends中装的都是JLFriend对象
        
        NSArray *dictArray = self.friends;
        NSMutableArray *tempArray = [NSMutableArray array];
        
        // 1,取出NSDictionary对象
        for (NSDictionary *dict in dictArray) {
            // 2,NSDictionary转模型对象
            JLFriend *friend = [JLFriend friendWithDict:dict];
            [tempArray addObject:friend];
        }
        
        // 3,对friends重新赋值,这样friends里面装的都是JLFriend对象
        self.friends = tempArray;
    }
    
    return self;
}

+ (instancetype)groupWithDict:(NSDictionary *)dict{

    return [[self alloc] initWithDict:dict];
}

@end
//
//  JLHeaderView.h
//  02-QQ好友列表
//
//  Created by XinYou on 15-3-6.
//  Copyright (c) 2015年 vxinyou. All rights reserved.
//

#import 
      
      
       
       

@class JLFriendGroup,JLHeaderView;

@protocol JLHeaderViewDelegate 
       
       
        
        

@optional
- (void)headerViewDidClickNameView:(JLHeaderView *)headerView;

@end


// 既然是自定义headerView,为什么还需要继承UItableViewHeaderFooterView,而不是继承UIView呢?
@interface JLHeaderView : UITableViewHeaderFooterView

@property (nonatomic,strong)JLFriendGroup *group;

@property (nonatomic,strong)id
        
        
          delegate; + (instancetype)headViewWithTableView:(UITableView *)tableView; @end // // JLHeaderView.m // 02-QQ好友列表 // // Created by XinYou on 15-3-6. // Copyright (c) 2015年 vxinyou. All rights reserved. // #import "JLHeaderView.h" #import "JLFriendGroup.h" @interface JLHeaderView() /** * 组名 */ @property (nonatomic,weak)UIButton *nameView; /** * 该组在线人数 */ @property (nonatomic,weak)UILabel *countView; @end @implementation JLHeaderView + (instancetype)headViewWithTableView:(UITableView *)tableView{ static NSString *ID = @"header"; // 在JLHeaderView.h中我们留下了一个疑问——“既然是自定义headerView,为什么还需要继承UItableViewHeaderFooterView,而不是继承UIView呢?” // 因为继承UItableViewHeaderFooterView可以像UITableViewCell一样对headerView进行复用,提升性能 JLHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID]; if (headerView == nil) { headerView = [[self alloc] initWithReuseIdentifier:ID]; } return headerView; } - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier{ // 在初始化方法中添加headerView的子控件 if (self = [super initWithReuseIdentifier:reuseIdentifier]) { // 1,添加组名控件 UIButton *nameView = [[UIButton alloc] init]; // UIButton *nameView = [UIButton buttonWithType:UIButtonTypeCustom];//和上面一句代码的作用一样 // nameView.backgroundColor = [UIColor redColor]; [self.contentView addSubview:nameView]; self.nameView = nameView; // 设置按钮的背景图片 [self.nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal]; [self.nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted]; // 设置按钮的文本内容与文本内容所在区域的边距 self.nameView.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0); // 设置按钮的内容与按钮四条边的边距 self.nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0); // 设置按钮的内容水平方向左对齐 self.nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; // 设置按钮的字体颜色 [self.nameView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // 设置按钮内部文字左边的图片 [self.nameView setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal]; // UIViewContentModeCenter : contents remain same size. positioned adjusted. // 意思是大小不变,位置居中。 // 假设imageView的高>宽,当imageView旋转90度后,就会变成宽>高, // 虽然居中显示,但是imageView的左边和右边还是会超出边框,所以还需要设置“超出边框的内容不需要裁剪” self.nameView.imageView.contentMode = UIViewContentModeCenter; // 超出边框的内容不需要裁剪 self.nameView.imageView.clipsToBounds = NO; // 给nameView设置监听 [self.nameView addTarget:self action:@selector(nameViewClick) forControlEvents:UIControlEventTouchUpInside]; // 此时self.bounds还没有值,这是为什么呢?因为这是UITableViewHeaderFooterView的初始化方法 // 假设我们初始化一个UILabel:UILabel *label = [[UILable alloc] init], // 经过这句代码后label的frame或者bounds属性都还是没有值的。 // self.nameView.frame = self.bounds; // 2,添加在线人数控件 UILabel *countView = [[UILabel alloc] init]; // countView.backgroundColor = [UIColor greenColor]; [self.contentView addSubview:countView]; self.countView = countView; // 设置UILabel中的文本右对齐 self.countView.textAlignment = NSTextAlignmentRight; // 设置UILabel的文本颜色 self.countView.textColor = [UIColor grayColor]; // 不能在这里设置frame // self.countView.frame = CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height) } return self; } /** * 当一个控件的frame发生改变的时候就会调用 * 一般在这个方法中设置子控件的frame */ - (void)layoutSubviews{ // 一定要调用父类的方法 [super layoutSubviews]; // 设置nameView这个Button填充父控件 self.nameView.frame = self.bounds; // 设置countView与父控件左边距为10,宽度150,高度=父控件高度 CGFloat padding = 10; CGFloat countW = 150; CGFloat countX = self.frame.size.width - padding - countW; CGFloat countY = 0; CGFloat countH = self.frame.size.height; self.countView.frame = CGRectMake(countX, countY, countW, countH); } - (void)setGroup:(JLFriendGroup *)group{ _group = group; // 设置组名 [self.nameView setTitle:group.name forState:UIControlStateNormal]; // 设置在线人数 self.countView.text = [NSString stringWithFormat:@"%d/%d", group.online, group.friends.count]; } - (void)nameViewClick{ // 设置该组的打开状态,对上一次状态取反 self.group.opened = !self.group.isOpened; // 通知代理(控制器),刷新数据 if ([self.delegate respondsToSelector:@selector(headerViewDidClickNameView:)]) { [self.delegate headerViewDidClickNameView:self]; } } /** * 当一个控件被添加到父控件中就会调用 * 在这里控制控制组名左边图片的旋转 为什么在这里控制图片的旋转呢? 当某组的headerView中的nameView被点击,触发了nameViewClick方法,该组的opened状态改变,然后控制器刷新数据 注意这里的刷新数据,会把之前UITableView中的数据全部销毁,然后全部重新创建,重新创建就需要把headerView添加到UITableView中。 所以didMoveToSuperView在每次刷新数据后都会调用,也就是每次点击nameView后都会调用 */ - (void)didMoveToSuperview{ if (self.group.opened) { // M_PI_2表示π/2 , M_2_PI表示2π self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2); } else { self.nameView.imageView.transform = CGAffineTransformMakeRotation(0); } } @end // // JLFriendCell.h // 02-QQ好友列表 // // Created by XinYou on 15-3-6. // Copyright (c) 2015年 vxinyou. All rights reserved. // #import 
         
           @class JLFriend; @interface JLFriendCell : UITableViewCell + (instancetype)cellWithTableView:(UITableView *)tableView; /** * friend是C++的关键字,不能作为属性名存在 */ @property (nonatomic,strong)JLFriend *friendData; @end // // JLFriendCell.m // 02-QQ好友列表 // // Created by XinYou on 15-3-6. // Copyright (c) 2015年 vxinyou. All rights reserved. // #import "JLFriendCell.h" #import "JLFriend.h" @implementation JLFriendCell + (instancetype)cellWithTableView:(UITableView *)tableView{ static NSString *ID = @"qq"; JLFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[JLFriendCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } return cell; } - (void)setFriendData:(JLFriend *)friendData{ _friendData = friendData; self.imageView.image = [UIImage imageNamed:_friendData.icon]; self.textLabel.text = _friendData.name; // vip红色昵称 self.textLabel.textColor = (_friendData.isVip ? [UIColor redColor] : [UIColor blackColor]); self.detailTextLabel.text = _friendData.intro; } @end 
          
        
       
       
      
      
     
     
    
    

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值