iOS UI-QQ聊天布局
一、Model
BWMessage.h
#import <Foundation/Foundation.h> typedef enum{
BWMessageMe = ,//表示自己
BWMessageOther = //表示对方
}BWMessageType; @interface BWMessage : NSObject
//消息正文
@property(nonatomic, copy) NSString *text;
//消息时间
@property(nonatomic, copy) NSString *time;
//消息类型
@property(nonatomic, assign) BWMessageType type; //记录是否隐藏时间
@property(nonatomic, assign) BOOL hideTime; - (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)messageWithDict:(NSDictionary *)dict; @end #import "BWMessage.h" @implementation BWMessage - (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
// _text = dict[@"text"];
// _time = dict[@"time"];
// _type =(BWMessageType)dict[@"type"];
[self setValuesForKeysWithDictionary:dict];
}
return self;
} + (instancetype)messageWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
} @end
BWMessageFrame.h
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h> #define textFont [UIFont systemFontOfSize:16] @class BWMessage; @interface BWMessageFrame : NSObject @property (nonatomic, strong) BWMessage *message;
@property (nonatomic, assign, readonly) CGRect timeFrame;
@property (nonatomic, assign, readonly) CGRect iconFrame;
@property (nonatomic, assign, readonly) CGRect textFrame; @property (nonatomic, assign, readonly) CGFloat rowHeight; @end #import "BWMessageFrame.h"
#import <UIKit/UIKit.h>
#import "BWMessage.h"
#import "NSString+BWTextSize.h" @implementation BWMessageFrame //重写setMessage
- (void)setMessage:(BWMessage *)message
{
_message = message; //计算每个控件的Frame //设置统一的间距
CGFloat margin = ;
//获取屏幕的宽度
CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
//计算时间label的frame
CGFloat timeX = ;
CGFloat timeY = ;
CGFloat timeW = screenW;
CGFloat timeH = ; if (!message.hideTime) {
//如果需要时间Label,那么再计算frame
_timeFrame = CGRectMake(timeX, timeY, timeW, timeH);
} //计算头像的frame
CGFloat iconW = ;
CGFloat iconH = ;
CGFloat iconY = CGRectGetMaxY(_timeFrame);
CGFloat iconX = message.type == BWMessageOther ? margin : screenW - iconW - margin;
_iconFrame = CGRectMake(iconX, iconY, iconW, iconH); //计算正文的frame
CGSize textSize = [message.text sizeOfTextWithMaxsize:CGSizeMake(, MAXFLOAT) andFont:textFont];
CGFloat textW = textSize.width+;
CGFloat textH = textSize.height+;
CGFloat textY = iconY;
CGFloat textX = message.type == BWMessageOther ? CGRectGetMaxX(_iconFrame) : screenW - margin - iconW - textW;
_textFrame = CGRectMake(textX, textY, textW, textH); //计算行高
//获取 头像的最大Y值和正文的最大Y值,然后用最大Y值+margin
CGFloat maxY = MAX(CGRectGetMaxY(_iconFrame), CGRectGetMaxY(_textFrame));
_rowHeight = maxY + margin; } @end
NSString+BWTextSize.h
// NSString+BWTextSize.h
// IOS_QQ聊天
//
// Created by ma c on 16/1/10.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface NSString (BWTextSize) //对象方法-计算文本尺寸
- (CGSize)sizeOfTextWithMaxsize:(CGSize)maxSize andFont:(UIFont *)font; //类方法-计算文本尺寸
+ (CGSize)sizeWithText:(NSString *)text andMaxSize:(CGSize)maxSize andFont:(UIFont *)font; @end // NSString+BWTextSize.m
// IOS_QQ聊天
//
// Created by ma c on 16/1/10.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import "NSString+BWTextSize.h" @implementation NSString (BWTextSize) - (CGSize)sizeOfTextWithMaxsize:(CGSize)maxSize andFont:(UIFont *)font
{
NSDictionary *attr = @{NSFontAttributeName : font};
return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil].size;
} + (CGSize)sizeWithText:(NSString *)text andMaxSize:(CGSize)maxSize andFont:(UIFont *)font
{
return [text sizeOfTextWithMaxsize:maxSize andFont:font];
} @end
三、View
// BWMessageCell.h
// IOS_QQ聊天
//
// Created by ma c on 16/1/10.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import <UIKit/UIKit.h>
@class BWMessageFrame; @interface BWMessageCell : UITableViewCell @property (nonatomic, strong) BWMessageFrame *messageFrame; + (instancetype) messageCellWithTableView:(UITableView *)tableView; @end // BWMessageCell.m
// IOS_QQ聊天
//
// Created by ma c on 16/1/10.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import "BWMessageCell.h"
#import "BWMessage.h"
#import "BWMessageFrame.h" @interface BWMessageCell () @property (nonatomic, strong) UILabel *lblTime;
@property (nonatomic, strong) UIImageView *imgViewHead;
@property (nonatomic, strong) UIButton *btnText; @end @implementation BWMessageCell //创建自定义Cell
+ (instancetype)messageCellWithTableView:(UITableView *)tableView
{
NSString *cellIdentifier = @"cellIdentifier";
BWMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[BWMessageCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
//设置单元格的背景颜色
cell.backgroundColor = [UIColor clearColor];
return cell;
} #pragma mark - 重写initWithStyle的方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
//创建子控件 //显示时间的label
self.lblTime = [[UILabel alloc] init];
self.lblTime.textAlignment = NSTextAlignmentCenter;
self.lblTime.font = [UIFont systemFontOfSize:];
[self.contentView addSubview:self.lblTime]; //显示头像的UIImageView
self.imgViewHead = [[UIImageView alloc] init];
[self.contentView addSubview:self.imgViewHead]; //显示正文的按钮
self.btnText = [[UIButton alloc] init];
self.btnText.titleLabel.font = textFont;
[self.btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
self.btnText.titleLabel.numberOfLines = ;
//self.btnText.backgroundColor = [UIColor purpleColor];
//self.btnText.titleLabel.backgroundColor = [UIColor redColor]; //设置按钮的内边距
self.btnText.contentEdgeInsets = UIEdgeInsetsMake(, , , );
[self.contentView addSubview:self.btnText];
}
return self;
}
#pragma mark - 重写setMessageFrame的方法
- (void)setMessageFrame:(BWMessageFrame *)messageFrame
{
_messageFrame = messageFrame; //获取数据模型
BWMessage *message = messageFrame.message; //分别设置控件的数据和frame //设置时间的内容和frame
self.lblTime.text = message.time;
self.lblTime.frame = messageFrame.timeFrame;
self.lblTime.hidden = message.hideTime; //设置头像的图片和frame
//根据消息类型,判断应该使用哪张图片
NSString *iconImg = message.type == BWMessageMe ? @"me" : @"other";
self.imgViewHead.image = [UIImage imageNamed:iconImg];
self.imgViewHead.frame = messageFrame.iconFrame; //设置正文的内容和frame
[self.btnText setTitle:message.text forState:UIControlStateNormal];
self.btnText.frame = messageFrame.textFrame; //设置正文的背景图
NSString *imgNor,*imgHighlighted;
if (message.type == BWMessageMe) {
//自己发送的消息
imgNor = @"chat_send_nor";
imgHighlighted = @"chat_send_press_pic";
//设置消息字体的颜色
[self.btnText setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
else{
//对方发送的消息
imgNor = @"chat_recive_nor";
imgHighlighted = @"chat_recive_press_pic";
//设置消息的字体颜色
[self.btnText setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
//加载图片
UIImage *imageNor = [UIImage imageNamed:imgNor];
UIImage *imageHighlighted = [UIImage imageNamed:imgHighlighted]; //用平铺的方式拉伸图片
imageNor = [imageNor stretchableImageWithLeftCapWidth:imageNor.size.width/ topCapHeight:imageNor.size.height/];
imageHighlighted = [imageHighlighted stretchableImageWithLeftCapWidth:imageHighlighted.size.width/ topCapHeight:imageHighlighted.size.height/]; //设置背景图
[self.btnText setBackgroundImage:imageNor forState:UIControlStateNormal];
[self.btnText setBackgroundImage:imageHighlighted forState:UIControlStateHighlighted]; } - (void)awakeFromNib {
// Initialization code
} - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated]; // Configure the view for the selected state
} @end
三、Controller
// ViewController.m
// IOS_QQ聊天
//
// Created by ma c on 16/1/9.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import "ViewController.h"
#import "BWMessage.h"
#import "BWMessageFrame.h"
#import "BWMessageCell.h" @interface ViewController ()<UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
//消息的Frame模型对象
@property (nonatomic, strong) NSMutableArray *arrMessageFrame; @property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *textInput; @end @implementation ViewController #pragma mark - 文本框代理方法 //return键被单击的时候触发
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
//1.获取用户输入的文本
NSString *text = textField.text; //2.发送用户的消息
[self sendMessage:text withType:BWMessageMe]; //3.发送系统的消息
[self sendMessage:@"不认识" withType:BWMessageOther]; //4.清空文本框
textField.text = nil; return YES;
}
//发送消息
- (void)sendMessage:(NSString *)msg withType:(BWMessageType)type
{
//1.创建一个数据模型和frame模型
//数据模型
BWMessage *model = [[BWMessage alloc] init];
//获取当前系统时间
NSDate *nowDate = [NSDate date];
//创建一个日期格式化器
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
//设置格式
formatter.dateFormat = @"今天:HH:mm";
//进行日期的格式化
model.time = [formatter stringFromDate:nowDate];
model.type = type;
model.text = msg; //frame模型
BWMessageFrame *frameModel = [[BWMessageFrame alloc] init];
frameModel.message = model;
//根据当前的消息时间和上一条消息的时间,来设置是否隐藏时间Label
BWMessageFrame *lastMessageFrame = [self.arrMessageFrame lastObject];
NSString *lastTime = lastMessageFrame.message.time;
if ([model.time isEqualToString:lastTime]) {
model.hideTime = YES;
} //2.把frame模型加载到集合中
[self.arrMessageFrame addObject:frameModel]; //3.刷新UITableView数据
[self.tableView reloadData]; //4.把最后一行滚动到最上面
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.arrMessageFrame.count - inSection:];
[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
} #pragma mark - 滚动视图代理方法
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//[self.textInput resignFirstResponder];
//滚动把键盘叫回去
[self.view endEditing:YES];
} #pragma mark - 数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.arrMessageFrame.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.获取模型数据
BWMessageFrame *frameModel = self.arrMessageFrame[indexPath.row];
//2.创建单元格
BWMessageCell *cell = [BWMessageCell messageCellWithTableView:tableView];
//3.把模型赋值给单元格
cell.messageFrame = frameModel;
//4.返回单元格
return cell;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
BWMessageFrame *frameModel = self.arrMessageFrame[indexPath.row];
return frameModel.rowHeight;
} #pragma mark - 懒加载
- (NSMutableArray *)arrMessageFrame
{
if (_arrMessageFrame == nil) { NSString *path = [[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]; NSArray *arrDict = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *arrModel = [NSMutableArray array]; for (NSDictionary *dict in arrDict) {
//创建一个数据模型
BWMessage *dataModel = [BWMessage messageWithDict:dict];
//创建一个Frame模型
BWMessageFrame *modelFrame = [[BWMessageFrame alloc] init]; //获取上一个数据模型
BWMessage *lastMessage = (BWMessage *)[[arrModel lastObject] message];
//判断“当前的模型时间”是否和“上一个模型时间”一样
if ([dataModel.time isEqualToString:lastMessage.time]) {
dataModel.hideTime = YES;
}
else
{
dataModel.hideTime = NO;
} modelFrame.message = dataModel; //把Frame模型加载到arrModel模型数组中
[arrModel addObject:modelFrame];
}
_arrMessageFrame = arrModel;
}
return _arrMessageFrame;
} #pragma mark - 视图加载
- (void)viewDidLoad {
[super viewDidLoad];
//取消分割线
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
//设置TableView的背景色
self.tableView.backgroundColor = [UIColor colorWithRed:236.0/ green:236.0/ blue:236.0/ alpha:];
//设置TableView的行不允许被选中
self.tableView.allowsSelection = NO;
//设置文本框距离最左侧有一段距离
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(, , , )];
//把leftView设置给文本框
self.textInput.leftView = leftView;
self.textInput.leftViewMode = UITextFieldViewModeWhileEditing; //监听键盘的弹出事件
//1.创建一个NSNotificationCenter对象
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
//2.监听键盘弹出发出的通知
[center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; }
//通知关联方法
- (void)keyboardWillChangeFrame:(NSNotification *)noteInfo
{
// NSLog(@"通知的名称:%@",noteInfo.name);
// NSLog(@"通知的发布者:%@",noteInfo.object);
// NSLog(@"通知的内容:%@",noteInfo.userInfo);
//1.获取键盘显示完毕或者隐藏完毕后的Y值
CGRect rectEnd = [noteInfo.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardY = rectEnd.origin.y;
//用键盘的Y值减去屏幕的高度计算平移的值
CGFloat transformValue = keyboardY - self.view.frame.size.height; [UIView animateWithDuration:0.25 animations:^{ self.view.transform = CGAffineTransformMakeTranslation(, transformValue);
}]; //让UITableView的最后一行滚动到最上面
NSIndexPath *lastRowindexPath = [NSIndexPath indexPathForRow:self.arrMessageFrame.count - inSection:];
[self.tableView scrollToRowAtIndexPath:lastRowindexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
} - (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
} - (BOOL)prefersStatusBarHidden
{
return YES;
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end
iOS UI-QQ聊天布局的更多相关文章
- AJ学IOS(18)UI之QQ聊天布局_键盘通知实现自动弹出隐藏_自动回复
AJ分享,必须精品 先看图片 第一步完成tableView和Cell的架子的图 完善图片 键盘弹出设置后图片: 自动回复图: 粗狂的架子 tableView和Cell的创建 首相tableView为了 ...
- iOS UI基础-10.0 QQ聊天布局之键盘及文本使用
要实现的效果: 这里只说用到的几个知识点 1.图片包含文字 在设置文字的Frame的时候,使用背景(按钮)的尺寸,文字使用了内边距 背景图片,使用拉伸 /** * 返回一张可以随意拉伸不变形的图片 ...
- QQ聊天界面的布局和设计(IOS篇)-第一季
我写的源文件整个工程会再第二季中发上来~,存在百度网盘, 感兴趣的童鞋, 可以关注我的博客更新,到时自己去下载~.喵~~~ QQChat Layout - 第一季 一.准备工作 1.将假数据messa ...
- QQ聊天界面的布局和设计(IOS篇)-第二季
QQChat Layout - 第二季 本来第二季是快写好了, 也花了点功夫, 结果gitbook出了点问题, 给没掉了.有些细节可能会一带而过, 如有疑问, 相互交流进步~. 在第一季中我们完成了Q ...
- IOS详解TableView——对话聊天布局的实现
上篇博客介绍了如何使用UITableView实现类似QQ的好友界面布局.这篇讲述如何利用自定义单元格来实现聊天界面的布局. 借助单元格实现聊天布局难度不大,主要要解决的问题有两个: 1.自己和其他人说 ...
- Objective-c——UI基础开发第八天(QQ聊天界面)
一.知识点: QQ聊天界面 双模型的使用(dataModel和frameModel) UITextField的使用 通知的使用 拉伸图片的两种方法(slicing/image对象的resizeable ...
- 搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)
搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating ...
- Android—简单的仿QQ聊天界面
最近仿照QQ聊天做了一个类似界面,先看下界面组成(画面不太美凑合凑合呗,,,,):
- 高仿qq聊天界面
高仿qq聊天界面,给有需要的人,界面效果如下: 真心觉得做界面非常痛苦,给有需要的朋友. chat.xml <?xml version="1.0" encoding=&quo ...
- 【WPF】实现类似QQ聊天消息的界面
最近公司有个项目,是要求实现类似 QQ 聊天这种功能的. 如下图 这没啥难的,稍微复杂的也就表情的解析而已. 表情在传输过程中的实现参考了新浪微博,采用半角中括号代表表情的方式.例如:“abc[dog ...
随机推荐
- SQL学习之简单增删改查
SQL最常用的语句,就是增删改查: 增删改查的对象,分别是库(文件夹),表(文件),表的内容(表的记录): 一.创建一个基本的表 #create table Student_Info (Name VA ...
- Python Web学习笔记之TCP/IP、Http、Socket的区别
经常在笔试.面试或者工作的时候听到这些协议,虽然以前没怎么涉及过,但至少知道这些是和网络编程密不可分的知识,作为一个客户端开发程序员,如果可以懂得网络编程的话,他的作用和能力肯定会提升一个档次.原因很 ...
- JWT(Json web token)认证详解
JWT(Json web token)认证详解 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该to ...
- cnats 使用
1. 准备 yum install cmakeyum install gcc gcc-c++yum install ncurses ncurses-develyum install openssl o ...
- 06: Django Admin
目录:Django其他篇 01:Django基础篇 02:Django进阶篇 03:Django数据库操作--->Model 04: Form 验证用户数据 & 生成html 05:Mo ...
- "1130-host ... is not allowed to connect to this MySql server"登录失败
原因: 该用户没有远程连接权限. 解决:授权! mysql>GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' IDENTIFIED BY 'password' ...
- xshell的Solarized Dark配色方案
之前在ubuntu, kali, mint, air下都使用这一款配色方案,后来在网上看到有人在xshell中使用,配色方案有分享,就是一起无法导入 原来这个东西在你现有的连接无法直接导入,需要重新打 ...
- linux下如何源码安装expect
1.作用 自动交互.比如如果用ssh登陆服务器,每次都输入密码,然而你觉得麻烦,那你就可以使用expect来做自动交互,这样的话就不用每次都输入密码 2.依赖 依赖tcl 3.获取源码 wget ht ...
- about MySQL Workbench的基本使用及运用操作
http://blog.csdn.net/dongdong9223/article/details/48318877 <大神整理的更好!(评论里还有其他整理的) ↑ 使用MySQL Work ...
- BZOJ 1001: [BeiJing2006]狼抓兔子(s-t平面图+最短路求最小割)
http://www.lydsy.com/JudgeOnline/problem.php?id=1001 题意: 思路:这道题目是最小割题目,但是吧你直接套用Dinic是会超时的. 这里有种很奇妙的做 ...