AJ分享,必须精品

先看效果图

哈哈,这次猫猫给来个动态的图片,这个看起来带劲

实现思路

首先建立模型

这里用到的是一个双层的模型。

cell的实现

这里一看其实就知道是一个tableView,我们自定义cell实现细节

headerView的实现

每一组的标题头其实都是headerVIew这里都是按钮需要我们自己设计。

代码实现

双层模型的代码

FriendCell:

#import <Foundation/Foundation.h>
#import "NJGlobal.h" @interface NJFriendModel : NSObject
// 头像
@property (nonatomic, copy) NSString *icon;
// 简介
@property (nonatomic, copy) NSString *intro;
// 昵称
@property (nonatomic, copy) NSString *name;
// 是否是vip
@property (nonatomic, assign, getter = isVip) BOOL vip; NJInitH(friend)
@end

QQGroupModel:

#import <Foundation/Foundation.h>
#import "NJGlobal.h" @interface NJQQGroupModel : NSObject
/// 存放当前组所有的好友信息(好友模型)
@property (nonatomic, strong) NSArray *friends; // 分组名称
@property (nonatomic, copy) NSString *name; // 在线人数
@property (nonatomic, copy) NSString *online; // 记录当前组是否需要打开
@property (nonatomic, assign, getter = isOpen) BOOL open; NJInitH(qqGroup)
@end @implementation NJQQGroupModel - (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
// 1.将字典转换成模型
[self setValuesForKeysWithDictionary:dict];
// 定义数组保存转换后的模型
NSMutableArray *models = [NSMutableArray arrayWithCapacity:self.friends.count];
// 2.特殊处理friends中的数据
for (NSDictionary *dict in self.friends) {
// 2.1转换为模型
NJFriendModel *friend = [NJFriendModel friendWithDict:dict];
[models addObject:friend]; }
self.friends = models;
}
return self;
} + (instancetype)qqGroupWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict]; }
@end

cell 的自定义

#import <UIKit/UIKit.h>
@class NJFriendModel; @interface NJFriendCell : UITableViewCell + (instancetype)cellWithTableView:(UITableView *)tableView; @property (nonatomic, strong) NJFriendModel *friendData; @end @implementation NJFriendCell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *identifier = @"friend";
NJFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[NJFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
return cell;
} - (void)setFriendData:(NJFriendModel *)friendData
{
_friendData = friendData; // 1.设置头像
self.imageView.image = [UIImage imageNamed:_friendData.icon];
// 2.设置昵称
self.textLabel.text = _friendData.name;
// 3.设置简介
self.detailTextLabel.text = _friendData.intro; // 4.判断是否是会员
if (_friendData.isVip) {
[self.textLabel setTextColor:[UIColor redColor]];
}else
{
[self.textLabel setTextColor:[UIColor blackColor]];
}
}
@end

header的自定义

#import "NJHeaderView.h"
#import "NJQQGroupModel.h" #import <UIKit/UIKit.h>
@class NJFriendModel; @interface NJFriendCell : UITableViewCell + (instancetype)cellWithTableView:(UITableView *)tableView; @property (nonatomic, strong) NJFriendModel *friendData; @end @implementation NJFriendCell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *identifier = @"friend";
NJFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[NJFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
return cell;
} - (void)setFriendData:(NJFriendModel *)friendData
{
_friendData = friendData; // 1.设置头像
self.imageView.image = [UIImage imageNamed:_friendData.icon];
// 2.设置昵称
self.textLabel.text = _friendData.name;
// 3.设置简介
self.detailTextLabel.text = _friendData.intro; // 4.判断是否是会员
if (_friendData.isVip) {
[self.textLabel setTextColor:[UIColor redColor]];
}else
{
[self.textLabel setTextColor:[UIColor blackColor]];
}
}
@end @interface NJHeaderView ()
@property (nonatomic, weak) UIButton *btn;
@property (nonatomic, weak) UILabel *label;
@end @implementation NJHeaderView // 创建头部视图
+ (instancetype)headerViewWithTableView:(UITableView *)tableView
{
// 1.创建头部视图
static NSString *identifier = @"header";
NJHeaderView *headderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
if (headderView == nil) {
headderView = [[NJHeaderView alloc] initWithReuseIdentifier:identifier];
}
return headderView;
} // 但凡在init方法中获取到的frame都是0
- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
// 1.添加子控件
// 1.1添加按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
// 监听按钮的点击事件
[btn addTarget:self action:@selector(btnOnClick:) forControlEvents:UIControlEventTouchUpInside];
// 设置按钮的背景图片
[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];
// 1.设置按钮的内容左对齐
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
// 2.设置按钮的内边距,然按钮的内容距离左边有一定的距离
btn.contentEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0);
// 3.设置按钮的标题和图片之间的距离
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0);
// btn.imageEdgeInsets
// 设置按钮标题颜色
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // 设置btn中的图片不填充整个imageview
btn.imageView.contentMode = UIViewContentModeCenter;
// 超出范围的图片不要剪切
// btn.imageView.clipsToBounds = NO;
btn.imageView.layer.masksToBounds = NO; [self addSubview:btn];
self.btn = btn; // 1.2添加label
UILabel *label = [[UILabel alloc] init];
// label.backgroundColor = [UIColor greenColor];
// 设置文本右对齐
label.textAlignment = NSTextAlignmentRight;
label.textColor = [UIColor grayColor]; [self addSubview:label];
self.label = label;
} // NSLog(@"initWithReuseIdentifier = %@", NSStringFromCGRect(self.frame));
return self;
}
// 该方法在控件的frame被改变的时候就会调用
// 该方法一般用于调整子控件的位置
- (void)layoutSubviews
{
#warning 切记重写layoutSubviews方法一定要调用父类的layoutSubviews
[super layoutSubviews];
// 1.设置按钮的frame
self.btn.frame = self.bounds;
// 2.设置label的frame
CGFloat padding = 20;// 间隙
CGFloat labelY = 0;
CGFloat labelH = self.bounds.size.height;
CGFloat labelW = 150;
CGFloat labelX = self.bounds.size.width - padding - labelW;
self.label.frame = CGRectMake(labelX, labelY, labelW, labelH);
} - (void)btnOnClick:(UIButton *)btn
{
NSLog(@"按钮被点击了");
// 1.修改组模型的isOpen属性
// 修改模型数据数据
self.qqGroup.open = !self.qqGroup.isOpen;
// 2. 刷新表格(通知代理)
if ([self.delegate respondsToSelector:@selector(headerViewDidClickHeaderView:)]) {
[self.delegate headerViewDidClickHeaderView:self];
} // 3.修改btn上图片,让图片旋转
// self.btn.imageView.transform = CGAffineTransformMakeRotation(M_PI_2); // NSLog(@"%p %@", self, self.qqGroup.name);
} #pragma mark - 当一个控件被添加到其它视图上的时候会调用以下方法
// 已经被添加到父视图上的时候会调用
- (void)didMoveToSuperview
{
// 在这个方法中就快要拿到最新的被添加到tableview上的头部视图修改它的图片
if (self.qqGroup.isOpen) {
self.btn.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
}
}
// 即将被添加到父视图上的时候会调用
- (void)willMoveToSuperview:(UIView *)newSuperview
{
// NSLog(@"willMoveToSuperview");
} - (void)setQqGroup:(NJQQGroupModel *)qqGroup
{
_qqGroup = qqGroup; // 1.设置按钮上的文字
[self.btn setTitle:_qqGroup.name forState:UIControlStateNormal];
// 2.设置在线人数
self.label.text = [NSString stringWithFormat:@"%@/%d", _qqGroup.online, _qqGroup.friends.count];
}
@end

控制器代码

#import "NJViewController.h"
#import "NJQQGroupModel.h"
#import "NJFriendModel.h"
#import "NJFriendCell.h"
#import "NJHeaderView.h" @interface NJViewController ()<NJHeaderViewDelegate>
// 保存所有的分组数据
@property (nonatomic, strong) NSArray *qqGroups; @end @implementation NJViewController #pragma mark - 懒加载
- (NSArray *)qqGroups
{
if (_qqGroups == nil) {
NSString *fullPath = [[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil];
NSArray *dictArray = [NSArray arrayWithContentsOfFile:fullPath];
NSMutableArray *models = [NSMutableArray arrayWithCapacity:dictArray.count];
for (NSDictionary *dict in dictArray) {
NJQQGroupModel *qqGroip = [NJQQGroupModel qqGroupWithDict:dict];
[models addObject:qqGroip];
}
self.qqGroups = [models copy];
}
return _qqGroups;
} - (void)viewDidLoad
{
[super viewDidLoad];
} #pragma mark - 数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.qqGroups.count;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// 1.取出对应的组模型
NJQQGroupModel *qqGroup = self.qqGroups[section];
// 2.返回对应组中的好友数
// return qqGroup.friends.count;
// return 0;
if (qqGroup.isOpen) {
// 代表要展开
return qqGroup.friends.count;
}else
{
// 代表要合拢
return 0;
}
} - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.创建cell
NJFriendCell *cell = [NJFriendCell cellWithTableView:tableView];
// 2.传递模型
// 2.1.取出对应的组模型
NJQQGroupModel *qqGroup = self.qqGroups[indexPath.section];
NJFriendModel *friend = qqGroup.friends[indexPath.row];
cell.friendData = friend; // 3.返回cell
return cell;
} #pragma mark - NJHeaderViewDelegate
- (void)headerViewDidClickHeaderView:(NJHeaderView *)headerView
{
// 重新调用数据源的方法加载数据
[self.tableView reloadData];
} #pragma mark - 代理方法
// 当一个分组标题进入视野的时候就会调用该方法
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// 1.创建头部视图, 头部视图有默认的宽高,是系统自动设置
NJHeaderView *headerView = [NJHeaderView headerViewWithTableView:tableView];
// 设置当前控制器为代理
headerView.delegate = self; // 2.传递模型
NJQQGroupModel *qqGroup = self.qqGroups[section];
// 0 - 0x8fa7ef0
headerView.qqGroup = qqGroup;
NSLog(@"%d - %p", section, headerView);
// 3.返回头部视图
return headerView; }
// 设置分组头部标题的高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 44;
} - (BOOL)prefersStatusBarHidden
{
return YES;
}
@end

AJ学IOS(19)UI之QQ好友列表的更多相关文章

  1. AJ学IOS 之ipad开发qq空间项目横竖屏幕适配

    AJ分享,必须精品 一:效果图 先看效果 二:结构图 如图所示: 其中用到了UIView+extension分类 Masonry第三方框架做子控制器的适配 NYHomeViewController对应 ...

  2. iOS UITableView制作类似QQ好友列表视图

                #import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDele ...

  3. iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一)

    iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一) 一.项目结构和plist文件 二.实现代码 1.说明: 主控制器直接继承UITableViewController // ...

  4. [iOS基础控件 - 6.9.3] QQ好友列表Demo TableView

    A.需求 1.使用plist数据,展示类似QQ好友列表的分组.组内成员显示缩进功能 2.组名使用Header,展示箭头图标.组名.组内人数和上线人数 3.点击组名,伸展.缩回好友组   code so ...

  5. android 实现QQ好友列表

    在某些Android开发群里,看到有些新手问怎么实现QQ好友列表,其实网上一搜挺多的.接触Android,也才一年的时间,大部分时间花在工作上(解bug...),界面上开发很少参与.自己维护的系统应用 ...

  6. Windows UIA自动化测试框架学习--获取qq好友列表

    前段时间应公司要求开发一款针对现有WPF程序的自动化测试工具,在网上查资料找了一段时间,发现用来做自动化测试的框架还是比较多的,比如python的两个模块pywinauto和uiautomation, ...

  7. 仿QQ好友列表界面的实现

    TableView有2种style:UITableViewStylePlain 和 UITableViewStyleGrouped. 但是QQ好友列表的tableView给人的感觉似乎是2个style ...

  8. ExpandableListView仿QQ好友列表

    本例中,对ExpandableListView中的数据进行了封装,分为两个JavaBean,一个为Group类表示组信息,一个Child类表示该组下子列表信息: Group: public class ...

  9. (二十七)QQ好友列表的实现

    QQ好友列表通过plist读取,plist的结构为一组字典,每个字典内有本组的信息和另外一组字典代表好友. 要读取plist,选择合适的数据结构,例如NSArray,然后调用initWithConte ...

随机推荐

  1. spring给容器中注入组件的几种方式

    目录 环境搭建 spring给容器中注入组件 1.包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)适用于把自己写的类加入组件(默认ID类名 ...

  2. iOS 指纹认证登陆开发(TouchID)

    设计思路 TouchID 关联账号 用户登陆成功 -> 开启TouchID登陆 -> TouchID验证 -> 记录用户信息(验证通过) -> 关联完成 TouchID 登陆 ...

  3. Journal of Proteome Research | iHPDM: In Silico Human Proteome Digestion Map with Proteolytic Peptide Analysis and Graphical Visualizations(iHPDM: 人类蛋白质组理论酶解图谱的水解肽段分析和可视化展示)| (解读人:邓亚美)

    文献名:iHPDM: In Silico Human Proteome Digestion Map with Proteolytic Peptide Analysis and Graphical Vi ...

  4. Python-时间戳、元组时间的格式、自定义时间格式之间的转换

    一.时间戳.元组时间的格式.自定义时间格式之间的转换 1.下面是三者之间的转换关系: 2.代码如下: import time import datetime print(time.time()) #获 ...

  5. spring的ioc依赖注入的三种方法(xml方式)

    常见的依赖注入方法有三种:构造函数注入.set方法注入.使用P名称空间注入数据.另外说明下注入集合属性 先来说下最常用的那个注入方法吧. 一.set方法注入 顾名思义,就是在类中提供需要注入成员的 s ...

  6. 解析“60k”大佬的19道C#面试题(下)

    解析"60k"大佬的19道C#面试题(下) 在上篇中,我解析了前 10 道题目,本篇我将尝试解析后面剩下的所有题目. 姐妹篇:解析"60k"大佬的19道C#面试 ...

  7. mysql事务提交和回滚机制

    应用场景:   银行取钱,从ATM机取钱,分为以下几个步骤       1 登陆ATM机,输入密码:    2 连接数据库,验证密码:    3 验证成功,获得用户信息,比如存款余额等:    4 用 ...

  8. 使用Keras进行深度学习:(五)RNN和双向RNN讲解及实践

    欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 笔者:Ray 介绍 通过对前面文章的学习,对深度神经网络(DNN) ...

  9. ClickHouse学习系列之二【用户权限管理】

    背景 最近花了些时间看了下ClickHouse文档,发现它在OLAP方面表现很优异,而且相对也比较轻量和简单,所以准备入门了解下该数据库系统.在安装完之后首先做的应该如何设置用户密码以及权限控制.因为 ...

  10. Arcgis中制作热力图

    摘要 使用核函数根据点或折线 (polyline) 要素计算每单位面积的量值以将各个点或折线 (polyline) 拟合为光滑锥状表面. 插图