iOS实战项目开发:QQ列表展示

  • 准备工作:
    好友列表plist文件


    iOS实战项目开发:QQ列表展示_第1张图片
    Paste_Image.png

头像:


iOS实战项目开发:QQ列表展示_第2张图片
Paste_Image.png
  • 第一步,创建数据模型,根据Plist文件创建
  • 好友Model

#import 

@interface JFriendsModel : NSObject

@property(nonatomic, copy) NSString * icon;   // 头像
@property(nonatomic, copy) NSString * name; // 姓名
@property(nonatomic, copy) NSString * intro; // 签名
@property(nonatomic, assign) BOOL  isVip; // vip

- (instancetype)initWithDict:(NSDictionary *)dict; // 初始化方法
+ (instancetype)friendWithDict:(NSDictionary *)dict; // 遍历构造器

@end```

- 方法实现

import "JFriendsModel.h"

@implementation JFriendsModel

  • (instancetype)initWithDict:(NSDictionary *)dict
    {
    if (self = [super init]) {
    [self setValuesForKeysWithDictionary:dict];
    }
    return self;
    }
  • (instancetype)friendWithDict:(NSDictionary *)dict
    {
    return [[self alloc] initWithDict:dict];
    }

@end```

  • Section模型的创建与好友模型创建的方法大致相同
#import 

@class JFriendsModel;
@interface JGroupModel : NSObject

@property (nonatomic, copy) NSString *name; // 分组名称
@property (nonatomic, copy) NSString *online;   // 在线人数
@property (nonatomic, strong) NSArray *friends; // 好友数组
@property(nonatomic, strong) JFriendsModel * friendModel;   // 好友Model
@property(nonatomic, assign) BOOL  isOpen;  // 点击展开或者关闭状态

- (instancetype)initWithDict:(NSDictionary *)dict;  // 初始化方法
+ (instancetype)groupWithDict:(NSDictionary *)dict; // 遍历构造器

@end```

- 方法实现

import "JGroupModel.h"

import "JFriendsModel.h"

@implementation JGroupModel

/**

  • 初始化方法
  • @param dict 外界传过来的字典
  • @return self
    */
  • (instancetype)initWithDict:(NSDictionary *)dict
    {
    if (self = [super init]) {
    [self setValuesForKeysWithDictionary:dict]; // 赋值
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.friends.count]; // 创建可变数组
    for (NSDictionary *dict in self.friends) { // 遍历好友数组
    JFriendsModel *friendModel = [JFriendsModel friendWithDict:dict]; // 初始化好友模型
    [array addObject:friendModel]; // 装入可变数组
    }
    self.friends = array; // 赋值给好友数组
    }
    return self;
    }

/**

  • 遍历构造器
  • @param dict 外界传入的字典
  • @return self实例对象
    */
  • (instancetype)groupWithDict:(NSDictionary *)dict
    {
    return [[self alloc] initWithDict:dict];
    }

@end```

  • 模型创建好之后,我们来写一个继承自UITableViewHeaderFooterView的头视图View
#import 
#import "JGroupModel.h"

/**
 *  头视图的代理方法
 */
@protocol HeaderViewDelegate 

@optional

- (void)clickView;  // 点击头视图事件

@end

@interface HeaderView : UITableViewHeaderFooterView

@property (nonatomic, assign) id delegate;  // 代理
@property (nonatomic, strong) JGroupModel *groupModel;  // 头视图数据模型

+ (instancetype)headerView:(UITableView *)tableView;    // 初始化方法

@end```

- 方法实现

import "HeaderView.h"

import "JGroupModel.h"

@implementation HeaderView{
UIButton *_arrowButton; // 点击按钮
UILabel *_label; // 标题
}

  • (instancetype)headerView:(UITableView *)tableView
    {
    static NSString *identifier = @"header"; // 重用
    HeaderView *headerView = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!headerView) {
    headerView = [[HeaderView alloc] initWithReuseIdentifier:identifier];
    }
    return headerView;
    }
  • (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
    {
    if (self == [super init]) {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setBackgroundImage:[UIImage imageNamed:@"header_bg"] forState:UIControlStateNormal]; // 背景图片
    [button setBackgroundImage:[UIImage imageNamed:@"header_bg_highlighted"] forState:UIControlStateHighlighted]; // 点击状态下的背景图片
    [button setImage:[UIImage imageNamed:@"arrow"] forState:UIControlStateNormal]; // 图片
    [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // button文字颜色
    // 设置Button按钮内容的内边距
    [button setContentEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
    // 设置Button内容的位置居左
    [button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
    // 设置Button标题的内边距
    [button setTitleEdgeInsets:UIEdgeInsetsMake(0, 20, 0, 0)];
    // 设置button图片的位置
    [button setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
    [button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
    button.imageView.clipsToBounds = NO; // 取消button图片自动修剪属性
    _arrowButton = button; // 赋值
    [self addSubview:_arrowButton];

      // 创建label显示在线人数
      UILabel *labelRight = [[UILabel alloc] init];
      labelRight.textAlignment = NSTextAlignmentCenter;
      _label = labelRight;
      [self addSubview:_label];
    

    }

    return self;
    }

pragma mark - buttonAction

  • (void)buttonAction
    {
    self.groupModel.isOpen = !self.groupModel.isOpen; // 设置属性为非

    // 如果代理响应了代理方法,就要调用这个方法
    if ([self.delegate respondsToSelector:@selector(clickView)]) {
    [self.delegate clickView];
    }
    }

pragma mark - 调用系统方法对button的箭头图片实现旋转

  • (void)didMoveToSuperview
    {
    // 根据isOpen属性判断是否旋转?如果为YES,则旋转90°,否则不旋转
    _arrowButton.imageView.transform = self.groupModel.isOpen ? CGAffineTransformMakeRotation(M_PI_2) : CGAffineTransformMakeRotation(0);
    }

pragma mark - 系统方法设置Frame值

  • (void)layoutSubviews
    {
    [super layoutSubviews];
    _arrowButton.frame = self.bounds; // 注意这里要设置为bounds 不然会出错
    _label.frame = CGRectMake(self.frame.size.width - 70, 0, 60, self.frame.size.height);
    }

pragma mark - 属性set方法给控件赋值

  • (void)setGroupModel:(JGroupModel *)groupModel
    {
    _groupModel = groupModel;
    [_arrowButton setTitle:_groupModel.name forState:UIControlStateNormal]; // button标题
    _label.text = [NSString stringWithFormat:@"%@/%lu", _groupModel.online, (unsigned long)_groupModel.friends.count]; // label文字
    }
    @end```

  • UITableView的头视图 和 模型都创建好了 我们来写最后的主角,主TableView

#import "ListTableViewController.h"
#import "JGroupModel.h"
#import "JFriendsModel.h"
#import "HeaderView.h"
#import "ViewController.h"

@interface ListTableViewController ()   // 遵守代理

@property (nonatomic, strong) NSArray *dataArray;   // 数据数组

@end

@implementation ListTableViewController

// 懒加载
- (NSArray *)dataArray
{
    if (!_dataArray) {
        // 获取数据
        NSString *path = [[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil];
        NSArray *array = [NSArray arrayWithContentsOfFile:path];
        NSLog(@"%@", array);
        // 初始化可变数组,数量为获取到的数组的数量
        NSMutableArray *muArray = [NSMutableArray arrayWithCapacity:array.count];
        // 遍历
        for (NSDictionary *dict in array) {
            // 初始化分组模型
            JGroupModel *md = [JGroupModel groupWithDict:dict];
            // 添加至可变数组
            [muArray addObject:md];
        }
        // 赋值给本控制器数据数组
        _dataArray = [muArray copy];
    }
    return _dataArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 重设tableHeaderView的高度
    self.tableView.sectionHeaderHeight = 40;
    // 取出tableView多余的分割线
    [self clickExtraLine:self.tableView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.dataArray.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    JGroupModel *md = self.dataArray[section];
    // 判断是展开还是关闭,如果是展开则返回friend的个数,如果是关闭则返回0
    NSInteger count = md.isOpen ? md.friends.count : 0;
    return count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"friendCell";
//    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
// 以上不能用forIndexPath:indexPath这个方法,不然会出现重用的崩溃
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
    }
    JGroupModel *md = self.dataArray[indexPath.section];    // 现获取分组模型
    JFriendsModel *friendMd = md.friends[indexPath.row];    // 获取row模型
    // 赋值
    cell.imageView.image = [UIImage imageNamed:friendMd.icon];
    cell.textLabel.text = friendMd.name;
    cell.detailTextLabel.text = friendMd.intro;
    return cell;
}

// 点击进入详情
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    ViewController *vc = [[ViewController alloc] init];
    vc.view.backgroundColor = [UIColor redColor];
    [self.navigationController pushViewController:vc animated:YES];
}

#pragma mark - UITableView Delegate 
// 添加头视图
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    HeaderView *headView = [HeaderView headerView:tableView];
    headView.delegate = self;
    headView.groupModel = self.dataArray[section];  // 给头视图传递数据模型
    return headView;
}

#pragma mark - 代理方法的实现
- (void)clickView
{
    [self.tableView reloadData];
}

#pragma mark - 去掉多余的线
- (void)clickExtraLine:(UITableView *)tableView
{
    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [UIColor clearColor];
    [self.tableView setTableFooterView:view];
}

@end```

- 运行效果:

![QQList.gif](http://upload-images.jianshu.io/upload_images/189984-c5d1acad818a88f5.gif?imageView2/2/w/1240)

你可能感兴趣的:(iOS实战项目开发:QQ列表展示)