oc学习之路----QQ聊天界面
用到的技术:自定义cell,通知机制,代理模式 transform
1.自定义cell(通过代码自定义cell)
①首先新建一个类继承UITableViewCell
②重写initWithStyle:reuseIdentifier方法
这里只需要把所有要显示的子控件添加到contenView中,在这一步一般不需要设置属性的, 但是如果是一些子控件中一些静态的属性,字需要一次性设置的话,就在这里 设置,在重写frameSet方法的时候在把一些比较动态的数据填充上去以及设置
每个子控件的frame
③提供两个模型
数据模型:存放数据
frame模型:通过拿到数据模型来计算每一个空间的frame,并设置为readOnly
2.通知机制

由此可见,我们可以这样认为 ,在一个程序运行过程中,有很多控件向通知中心发送通知,而我们可以随时随地的接收想要的通知,这点类似于代理,但是区别于的代理的是,通知比代理灵活,而且通知是多对多关系,一个对象可以告诉N个对象发生什么事情,一个对象能得知N个对象发生什么事情,而代理是一对一关系,一个对象只能告诉一个对象发生什么事情。
通知发布
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
//发布一个名称为aName的通知,anObject为这个通知的发布者,aUserInfo为额外信息
通知监听
通知中心提供方法来注册一个监听通知的监听器(换言之就是,将自定义通知公之于世)
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
/**
observer:监听器,即谁要接收这个通知
aSelector:收到通知后,回调监听器的这个方法,并且把通知对象当做参数传入
aName:通知的名称。如果为nil,那么无论通知的名称是什么,监听器都能收到这个通知
anObject:通知发布者。如果为anObject和aName都为nil,监听器都收到所有的通知*/
取消注册监听器
/*
通知中心不会保留(retain)监听器对象,在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃 通知中心提供了相应的方法来取消注册监听器
*/
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject; //一般在监听器销毁之前取消注册(如在监听器中加入下列代码):
- (void)dealloc {
//[super dealloc]; 非ARC中需要调用此句
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
通知监听
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
3 代理模式
简单步骤就是:一个协议 一个返回实现该协议的id类型的delegate 还有就是 在使用短实现协议,并且实现协议的方法
难点:自定义cell,聊天图片的无变化拉伸,键盘的监听
思路:新建模型一个计算位置的,一个填充数据的
新建View.用于显示每一个cell里面的数据m
细节:
/**
* 数据模型
* MessageDataModel.m
*/
@implementation MessageDataModel
+(instancetype)messageWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
-(instancetype)initWithDict:(NSDictionary *)dict{
if(self = [super init]){
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
/**
* 位置模型
* MessageFrameData.m
*/
#define MJTextFont [UIFont systemFontOfSize:15]
#import "MessageFrameData.h"
#import "MessageDataModel.h" @implementation MessageFrameData
-(void)setMessage:(MessageDataModel *)message {
_message = message;
// 间距
CGFloat padding = ;
// 屏幕的宽度
CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
NSLog(@"==========%f",screenW);
// 时间布局
if(!message.hideTime){
CGFloat timeX = ;
CGFloat timeY = ;
CGFloat timeW = screenW;
CGFloat timeH = ;
_timeF = CGRectMake(timeX, timeY, timeW, timeH);
} // 头像布局
CGFloat iconY = CGRectGetMaxY(_timeF)+padding;
CGFloat iconW = ;
CGFloat iconH = ;
CGFloat iconX;
if(message.type == MessageTypeOther){//别人发的
iconX = padding;
} else{//自己发的
iconX = screenW - padding -iconW;
}
_iconF = CGRectMake(iconX, iconY, iconW, iconH); // 正文
CGFloat textY = iconY;
// 能显示的最大size
CGSize textMaxSize = CGSizeMake(, MAXFLOAT);
// 文本的真实size
CGSize textSize = [self sizeWithText:message.text font:MJTextFont maxSize:textMaxSize];
// 最终确定的size;
CGSize textBtnSize = CGSizeMake(textSize.width+ TextPadding*, textSize.height+ TextPadding*);
CGFloat textX;
if(message.type == MessageTypeOther){
textX = CGRectGetMaxX(_iconF)+padding;
} else{
textX = iconX - padding -textBtnSize.width;
}
_textF = (CGRect){{textX,textY},textBtnSize};
// _textF = CGRectMake(textX, textY, textSize.width, textSize.height); CGFloat textMaxY = CGRectGetMaxY(_textF);
CGFloat iconMaxY = CGRectGetMaxY(_iconF);
_cellHeight = MAX(textMaxY, iconMaxY) + padding;
}
/**
* 计算文字尺寸
*
* @param text 需要计算尺寸的文字
* @param font 文字的字体
* @param maxSize 文字的最大尺寸
*/
- (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize
{
NSDictionary *attrs = @{NSFontAttributeName : font};
return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}
@end
/**
* 自定义cell,用于填充数据和设置frame
*/
#define MJTextFont [UIFont systemFontOfSize:15]
#import "QQQViewCellTableViewCell.h"
#import "MessageDataModel.h"
#import "UIImage+Extension.h" @interface QQQViewCellTableViewCell()
//内容
@property (nonatomic, weak) UIButton *textView;
//发送时间
@property (nonatomic, weak) UIImageView *iconView;
@property (nonatomic, weak)UILabel *timeView;
@end @implementation QQQViewCellTableViewCell /**
* 重写
*/
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
// 先调用父类方法
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self){
// 子空间的创建和初始化
// 时间
UILabel *timeView = [[UILabel alloc] init];
timeView.textAlignment = NSTextAlignmentCenter;
timeView.textColor = [UIColor grayColor];
timeView.font = [UIFont systemFontOfSize:];
[self.contentView addSubview:timeView];
self.timeView = timeView; // 头像
UIImageView *iconView = [[UIImageView alloc] init];
[self.contentView addSubview:iconView];
self.iconView = iconView; // 正文
UIButton *textView = [[UIButton alloc] init];
textView.titleLabel.numberOfLines = ;
// textView.backgroundColor = [UIColor grayColor];
textView.titleLabel.font = MJTextFont;
[textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
// 设置内边距
textView.contentEdgeInsets = UIEdgeInsetsMake(TextPadding, TextPadding, TextPadding, TextPadding);
[self.contentView addSubview:textView];
self.textView = textView; // 设置cell的背景颜色
self.backgroundColor = [UIColor clearColor];
}
return self;
} //这是布局
-(void)setModel:(MessageFrameData *)model {
_model = model;
MessageDataModel *message = model.message;
// 时间
self.timeView.text = message.time;
self.timeView.frame = model.timeF;
// 头像
NSString *icon = (message.type == MessageTypeOther)?@"other":@"me";
self.iconView.image = [UIImage imageNamed:icon];
self.iconView.frame = model.iconF;
// 正文
[self.textView setTitle:message.text forState:UIControlStateNormal];
self.textView.frame = model.textF;
// 设置正文背景图
if (message.type == MessageTypeMe){
[self.textView setBackgroundImage:[UIImage resizableImage:@"chat_send_nor"] forState:UIControlStateNormal];
} else{
[self.textView setBackgroundImage:[UIImage resizableImage:@"chat_recive_nor"] forState:UIControlStateNormal];
}
} +(instancetype)cellWithTableView:(UITableView *)tableView{
static NSString *ID = @"qqmessage";
QQQViewCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil){
cell = [[QQQViewCellTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
return cell;
} @end
oc学习之路----QQ聊天界面的更多相关文章
- Objective-c——UI基础开发第八天(QQ聊天界面)
一.知识点: QQ聊天界面 双模型的使用(dataModel和frameModel) UITextField的使用 通知的使用 拉伸图片的两种方法(slicing/image对象的resizeable ...
- QQ聊天界面的布局和设计(IOS篇)-第二季
QQChat Layout - 第二季 本来第二季是快写好了, 也花了点功夫, 结果gitbook出了点问题, 给没掉了.有些细节可能会一带而过, 如有疑问, 相互交流进步~. 在第一季中我们完成了Q ...
- QQ聊天界面的布局和设计(IOS篇)-第一季
我写的源文件整个工程会再第二季中发上来~,存在百度网盘, 感兴趣的童鞋, 可以关注我的博客更新,到时自己去下载~.喵~~~ QQChat Layout - 第一季 一.准备工作 1.将假数据messa ...
- 高仿qq聊天界面
高仿qq聊天界面,给有需要的人,界面效果如下: 真心觉得做界面非常痛苦,给有需要的朋友. chat.xml <?xml version="1.0" encoding=&quo ...
- 在WEB项目中调用QQ通讯组件打开QQ聊天界面
在很多WEB项目中,需要提供在线服务的功能,加上自己的联系方式,例如:QQ,不用添加QQ好友也可以交谈,那这到底是怎么实现的呢? 对于这个功能,需要提到一个组件,即“QQ通讯组件”.QQ通讯组件是一种 ...
- Android—简单的仿QQ聊天界面
最近仿照QQ聊天做了一个类似界面,先看下界面组成(画面不太美凑合凑合呗,,,,):
- Android 内部启动其他应用,以及打开指定qq聊天界面
在自己应用中打开第三方应用,有好多种方法,这里举例一种: //以打开微信为例,前提需要知道打开应用的包名,一般一个发布版本的应用,包名不会轻易改变的,但是,打开QQ就要注意了,毕竟QQ的发布版本有不下 ...
- Android 根据QQ号跳转到QQ聊天界面
从自己开发的应用中根据QQ号跳转到QQ应用的聊天界面,实现起来很方便: 即: startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(" ...
- 在移动网页网页上点击链接跳转到QQ聊天界面
打开qq聊天窗口的方法 <a href="http://wpa.qq.com/msgrd?v=3&uin=1450612626&site=qq&menu=yes ...
随机推荐
- 使用代理下载Android SDK
hx.gy:1080是红杏公益服务器,方便科学工作者访问一些常用的科学网站. 在Android SDK Manager中选择[Tools]->[Options],如下设置: HTTP Proxy ...
- 遍历DOM的所有节点,输出宽度高度都大于50的元素节点名称
需要注意的问题有几点: 1.遍历所有元素节点的方式是:document.getElementsByTagName("*"),同时为了兼容性好可以再一句:document.all 2 ...
- 浏览我的php网页时,出现的都是网页的代码
添加php模块 ,在apache/conf/httpd.conf,如果是windows下的话,添加如下代码,具体路径你根据具体情况设置#BEGIN PHP INSTALLER EDITS - REMO ...
- 过生日,也要学学哈,这次是SHELL的GETOPTS
今天是WEBSOCKET,, 先完成一个SHELL的GETOPS,周一就用得着. #!/bin/bash echo "usage: ./$0 -t (prism|opscripts)&quo ...
- 汇编 db,dw,dd的区别
db定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1 dw定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2 dd定义双字类型变量,一个双字数据占4个字节单元,读完一个, ...
- [状压dp]POJ2686 Traveling by Stagecoach
题意: m个城市, n张车票, 每张车票$t_i$匹马, 每张车票可以沿某条道路到相邻城市, 花费是路的长度除以马的数量. 求a到b的最小花费, 不能到达输出Impossible $1\le n\le ...
- codeforces Vasya and Digital Root
/* * c.cpp * * Created on: 2013-10-7 * Author: wangzhu */ /** * 当时比赛时,想得复杂了,也想偏了, * 1).写出来之后,结果达到了预期 ...
- c#中的delegate(委托)和event(事件)
c#中的delegate(委托)和event(事件) 一.delegate是什么东西? 完全可以把delegate理解成C中的函数指针,它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能 ...
- socket编程在windows和linux下的区别
如无其它说明,本文所指Linux均表示2.6内核Linux,GCC编译器,Windows均表示Windows XP系统,Visual Studio 2005 sp1编译环境. 下面大概分几个方面进行罗 ...
- CreateObject("Wscript.Shell")用法
WScript.Shell是WshShell对象的ProgID,创建WshShell对象可以运行程序.操作注册表.创建快捷方式.访问系统文件夹.管理环境变量. 该对象有一个run方法. Run 方法创 ...