[iOS基础控件 - 6.9.1] 聊天界面Demo 代码

时间:2022-09-17 16:35:00
框架:
[iOS基础控件 - 6.9.1] 聊天界面Demo 代码
 
所有代码文件
[iOS基础控件 - 6.9.1] 聊天界面Demo 代码
 
Model:
 //
// Message.h
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
//
// message信息模型,存储聊天记录 #import <Foundation/Foundation.h> typedef enum {
MessageTypeMe = , // 我发出的信息
MessageTypeOhter = // 对方发出的信息
} MessageType; @interface Message : NSObject /** 信息 */
@property(nonatomic, copy) NSString *text; /** 发送时间 */
@property(nonatomic, copy) NSString *time; /** 发送方 */
@property(nonatomic, assign) MessageType type; /** 是否隐藏发送时间 */
@property(nonatomic, assign) BOOL hideTime; - (instancetype) initWithDictionary:(NSDictionary *) dictionary;
+ (instancetype) messageWithDictionary:(NSDictionary *) dictionary;
+ (instancetype) message; @end
 
 //
// Message.m
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "Message.h" @implementation Message - (instancetype) initWithDictionary:(NSDictionary *) dictionary {
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dictionary];
} return self;
} + (instancetype) messageWithDictionary:(NSDictionary *) dictionary {
return [[self alloc] initWithDictionary:dictionary];
} + (instancetype) message {
return [self messageWithDictionary:nil];
} @end
 
 //
// MessageFrame.h
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
//
// 存储每个cell内子控件的位置尺寸的frame #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Message.h" #define MESSAGE_TIME_FONT [UIFont systemFontOfSize:13]
#define MESSAGE_TEXT_FONT [UIFont systemFontOfSize:15]
#define TEXT_INSET 20 @interface MessageFrame : NSObject /** 发送时间 */
@property(nonatomic, assign, readonly) CGRect timeFrame; /** 头像 */
@property(nonatomic, assign, readonly) CGRect iconFrame; /** 信息 */
@property(nonatomic, assign, readonly) CGRect textFrame; /** 信息model */
@property(nonatomic, strong) Message *message; /** cell的高度 */
@property(nonatomic, assign) CGFloat cellHeight; @end
 
 //
// MessageFrame.m
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "MessageFrame.h"
#import "NSString+Extension.h" @implementation MessageFrame /** 设置message,计算位置尺寸 */
- (void)setMessage:(Message *)message {
_message = message; // 间隙
CGFloat padding = ; // 1.发送时间
if (NO == message.hideTime) {
CGFloat timeWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat timeHeight = ;
CGFloat timeX = ;
CGFloat timeY = ;
_timeFrame = CGRectMake(timeX, timeY, timeWidth, timeHeight);
} // 2.头像
CGFloat iconWidth = ;
CGFloat iconHeight = ; // 2.1 根据信息的发送方调整头像位置
CGFloat iconX;
if (MessageTypeMe == message.type) {
// 我方,放在右边
iconX = [UIScreen mainScreen].bounds.size.width - padding - iconWidth;
} else {
// 对方,放在左边
iconX = padding;
} CGFloat iconY = CGRectGetMaxY(_timeFrame) + padding;
_iconFrame = CGRectMake(iconX, iconY, iconWidth, iconHeight); // 3.信息,尺寸可变
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
// 3.1 设置文本最大尺寸
CGSize textMaxSize = CGSizeMake(screenWidth - iconWidth - padding * , MAXFLOAT);
// 3.2 计算文本真实尺寸
CGSize textRealSize = [message.text sizeWithFont:MESSAGE_TEXT_FONT maxSize:textMaxSize]; // 3.3 按钮尺寸
CGSize btnSize = CGSizeMake(textRealSize.width + TEXT_INSET*, textRealSize.height + TEXT_INSET*); // 3.4 调整信息的位置
CGFloat textX;
if (MessageTypeMe == message.type) {
// 我方,放在靠右
textX = CGRectGetMinX(_iconFrame) - btnSize.width - padding;
} else {
// 对方,放在靠左
textX = CGRectGetMaxX(_iconFrame) + padding;
} CGFloat textY = iconY;
_textFrame = CGRectMake(textX, textY, btnSize.width, btnSize.height); // 4.cell的高度
CGFloat iconMaxY = CGRectGetMaxY(_iconFrame);
CGFloat textMaxY = CGRectGetMaxY(_textFrame);
_cellHeight = MAX(iconMaxY, textMaxY) + padding;
} @end
 
View:
 //
// MessageCell.h
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import <UIKit/UIKit.h> #define BACKGROUD_COLOR [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1.0] @class MessageFrame, Message; @interface MessageCell : UITableViewCell /** 持有存储了聊天记录和聊天框位置尺寸的frame */
@property(nonatomic, strong) MessageFrame *messageFrame; /** 传入父控件tableView引用的构造方法 */
+ (instancetype) cellWithTableView:(UITableView *) tableView; @end
 
 //
// MessageCell.m
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "MessageCell.h"
#import "MessageFrame.h"
#import "UIImage+Extension.h" @interface MessageCell() // 定义cell内的子控件,用于保存控件,然后进行数据和位置尺寸的计算
/** 发送时间 */
@property(nonatomic, weak) UILabel *timeLabel; /** 头像 */
@property(nonatomic, weak) UIImageView *iconView; /** 信息 */
@property(nonatomic, weak) UIButton *textView; @end @implementation MessageCell - (void)awakeFromNib {
// Initialization code
} - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated]; // Configure the view for the selected state
} #pragma mark - 构造方法
// 自定义构造方法
+ (instancetype) cellWithTableView:(UITableView *) tableView {
static NSString *ID = @"message"; // 使用缓存池
MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; // 创建一个新的cell
if (nil == cell) {
cell = [[MessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
} return cell;
} // 重写构造方法,创建cell中的各个子控件
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; // 设置cell的背景色
self.backgroundColor = BACKGROUD_COLOR; // 1.发送时间
UILabel *timeLabel = [[UILabel alloc] init];
[timeLabel setTextAlignment:NSTextAlignmentCenter];
[timeLabel setFont:MESSAGE_TIME_FONT];
[timeLabel setTextColor:[UIColor grayColor]];
[self.contentView addSubview:timeLabel];
self.timeLabel = timeLabel; // 2.头像
UIImageView *iconView = [[UIImageView alloc] init];
[self.contentView addSubview:iconView];
self.iconView = iconView; // 3.信息
UIButton *textView = [[UIButton alloc] init];
[textView setTitle:@"text" forState:UIControlStateNormal];
[textView.titleLabel setFont:MESSAGE_TEXT_FONT]; // 3.1 如果是浅色背景,记得设置字体颜色,因为按钮的字体颜色默认是白色
[textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[textView.titleLabel setNumberOfLines:]; // 设置自动换行 // 3.2 调整文字的内边距
textView.contentEdgeInsets = UIEdgeInsetsMake(TEXT_INSET, TEXT_INSET, TEXT_INSET, TEXT_INSET); [self.contentView addSubview:textView];
self.textView = textView; return self;
} #pragma mark - 加载数据
// 加载frame,初始化cell中子控件的数据、位置尺寸
- (void)setMessageFrame:(MessageFrame *) messageFrame {
_messageFrame = messageFrame; // 1.发送时间
self.timeLabel.text = messageFrame.message.time;
self.timeLabel.frame = messageFrame.timeFrame; // 2.头像
NSString *icon = (messageFrame.message.type == MessageTypeMe)? @"me":@"other";
self.iconView.image = [UIImage imageNamed:icon];
self.iconView.frame = messageFrame.iconFrame; // 3.信息
[self.textView setTitle:messageFrame.message.text forState:UIControlStateNormal];
self.textView.frame = messageFrame.textFrame; // 3.1 设置聊天框
NSString *chatImageNormalName;
NSString *chatImageHighlightedName;
if (MessageTypeMe == messageFrame.message.type) {
chatImageNormalName = @"chat_send_nor";
chatImageHighlightedName = @"chat_send_press_pic";
} else {
chatImageNormalName = @"chat_receive_nor";
chatImageHighlightedName = @"chat_receive_press_pic";
} UIImage *chatImageNormal = [UIImage resizableImage:chatImageNormalName];
UIImage *chatImageHighlighted = [UIImage resizableImage:chatImageHighlightedName];
[self.textView setBackgroundImage:chatImageNormal forState:UIControlStateNormal];
[self.textView setBackgroundImage:chatImageHighlighted forState:UIControlStateHighlighted];
} @end
 
Controller:
 //
// ViewController.m
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "ViewController.h"
#import "Message.h"
#import "MessageCell.h"
#import "MessageFrame.h" @interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate> /** 聊天区tableView */
@property (weak, nonatomic) IBOutlet UITableView *tableView; /** 信息记录数据 */
@property(nonatomic, strong) NSMutableArray *messages; /** 信息输入框 */
@property (weak, nonatomic) IBOutlet UITextField *inputView; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib. // 设置dataSource
self.tableView.dataSource = self; // 设置tableView的delegate
self.tableView.delegate = self; // 设置tableView背景色,当键盘呼出隐藏的时候,避免默认的黑色背景出现太突兀
self.tableView.backgroundColor = BACKGROUD_COLOR; // 设置聊天区TableView
// 不使用分割线
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// 禁止选中cell
[self.tableView setAllowsSelection:NO]; // 设置虚拟键盘监听器
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; // 设置TextField文字左间距
self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(, , , )];
self.inputView.leftViewMode = UITextFieldViewModeAlways; // 设置信息输入框的代理
self.inputView.delegate = self;
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (BOOL)prefersStatusBarHidden {
return YES;
} #pragma mark - 数据加载
/** 延迟加载plist文件数据 */
- (NSMutableArray *)messages {
if (nil == _messages) {
NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]]; NSMutableArray *mdictArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
Message *message = [Message messageWithDictionary:dict]; // 判断是否发送时间与上一条信息的发送时间相同,若是则不用显示了
MessageFrame *lastMessageFrame = [mdictArray lastObject];
if (lastMessageFrame && [message.time isEqualToString:lastMessageFrame.message.time]) {
message.hideTime = YES;
} MessageFrame *messageFrame = [[MessageFrame alloc] init];
messageFrame.message = message;
[mdictArray addObject:messageFrame];
} _messages = mdictArray;
} return _messages;
} #pragma mark - dataSource方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.messages.count;
} - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MessageCell *cell = [MessageCell cellWithTableView:self.tableView];
cell.messageFrame = self.messages[indexPath.row]; return cell;
} #pragma mark - tableView代理方法
/** 动态设置每个cell的高度 */
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
MessageFrame *messageFrame = self.messages[indexPath.row];
return messageFrame.cellHeight;
} #pragma mark - scrollView 代理方法
/** 点击拖曳聊天区的时候,缩回键盘 */
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
// 1.缩回键盘
[self.view endEditing:YES];
} #pragma mark - 监听事件
- (void) keyboardWillChangeFrame:(NSNotification *) note {
// 1.取得弹出后的键盘frame
CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; // 2.键盘弹出的耗时时间
CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]; // 3.键盘变化时,view的位移,包括了上移/恢复下移
CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height; [UIView animateWithDuration:duration animations:^{
self.view.transform = CGAffineTransformMakeTranslation(, transformY);
}];
} #pragma mark - TextField 代理方法
/** 回车响应事件 */
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// 我方发出信息
[self sendMessageWithContent:textField.text andType:MessageTypeMe]; // 自动回复
[self sendMessageWithContent:[NSString stringWithFormat:@"%@\n%@", textField.text, @"你妹!!!"] andType:MessageTypeOhter]; // 消除消息框内容
self.inputView.text = nil; [self.tableView reloadData]; // 滚动到最新的消息
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.messages.count - inSection:];
[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; return YES; // 返回值意义不明
} // 发送消息
- (void) sendMessageWithContent:(NSString *) text andType:(MessageType) type {
// 获取当前时间
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MMM-dd hh:mm:ss";
NSString *dateStr = [formatter stringFromDate:date]; // 我方发出信息
NSDictionary *dict = @{@"text":text,
@"time":dateStr,
@"type":[NSString stringWithFormat:@"%d", type]}; Message *message = [[Message alloc] init];
[message setValuesForKeysWithDictionary:dict];
MessageFrame *messageFrame = [[MessageFrame alloc] init];
messageFrame.message = message; [self.messages addObject:messageFrame];
} @end
工具类:
 //
// NSString+Extension.h
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
//
// NSString扩展类 #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> @interface NSString (Extension) /** 测量文本的尺寸 */
- (CGSize) sizeWithFont:(UIFont *)font maxSize:(CGSize) maxSize; @end
 
 //
// NSString+Extension.m
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "NSString+Extension.h" @implementation NSString (Extension) /** 测量文本的尺寸 */
- (CGSize)sizeWithFont:(UIFont *)font maxSize:(CGSize)maxSize {
NSDictionary *attrs = @{NSFontAttributeName: font};
CGSize size = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size; return size;
} @end
 
 //
// UIImage+Extension.h
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
//
// NSImage 类的扩展 #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> @interface UIImage (Extension) + (UIImage *) resizableImage:(NSString *) imageName; @end
 //
// UIImage+Extension.m
// QQChatDemo
//
// Created by hellovoidworld on 14/12/8.
// Copyright (c) 2014年 hellovoidworld. All rights reserved.
// #import "UIImage+Extension.h" @implementation UIImage (Extension) + (UIImage *) resizableImage:(NSString *) imageName {
UIImage *image = [UIImage imageNamed:imageName];
// 取图片中部的1 x 1进行拉伸
UIEdgeInsets insets = UIEdgeInsetsMake(image.size.height/, image.size.width/, image.size.height/ + , image.size.width/ + );
return [image resizableImageWithCapInsets:insets];
} @end
 
 

[iOS基础控件 - 6.9.1] 聊天界面Demo 代码的更多相关文章

  1. &lbrack;iOS基础控件 - 6&period;11&period;3&rsqb; 私人通讯录Demo 控制器的数据传递、存储

    A.需求 1.搭建一个"私人通讯录"Demo 2.模拟登陆界面 账号 密码 记住密码开关 自动登陆开关 登陆按钮 3.退出注销 4.增删改查 5.恢复数据(取消修改)   这个代码 ...

  2. &lbrack;iOS基础控件 - 3&period;1&rsqb; QQ登陆界面

      A.storyboard 控件版 1.label 2.textfield      a.Keyboard Type           账号:Number Pad           密码:Num ...

  3. &lbrack;iOS基础控件 - 5&period;5&rsqb; 代理设计模式 &lpar;基于”APP列表&quot&semi;练习&rpar;

    A.概述      在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能      1.按钮点击后,显示为“已下载”,并且不 ...

  4. &lbrack;iOS基础控件 - 6&period;9&rsqb; 聊天界面Demo

    A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话 ...

  5. iOS 基础控件(下)

    上篇介绍了UIButton.UILabel.UIImageView和UITextField,这篇就简短一点介绍UIScrollView和UIAlertView. UIScrollView 顾名思义也知 ...

  6. &lbrack;iOS基础控件 - 7&period;0&rsqb; UIWebView

    A.基本使用 1.概念 iOS内置的浏览器控件 Safari浏览器就是通过UIWebView实现的   2.用途:制作简易浏览器 (1)基本请求 创建请求 加载请求 (2)代理监听webView加载, ...

  7. &lbrack;iOS基础控件 - 6&period;10&period;2&rsqb; PickerView 自定义row内容 国家选择Demo

    A.需求 1.自定义一个UIView和xib,包含国家名和国旗显示 2.学习row的重用   B.实现步骤 1.准备plist文件和国旗图片     2.创建模型 // // Flag.h // Co ...

  8. iOS基础 - 控件属性

    一.控件的属性 1.CGRect frame 1> 表示控件的位置和尺寸(以父控件的左上角为坐标原点(0, 0)) 2> 修改这个属性,可以调整控件的位置和尺寸 2.CGPoint cen ...

  9. &lbrack;iOS基础控件 - 6&period;12&period;3&rsqb; &commat;property属性 strong weak copy

    A.概念 @property 的修饰词   strong: 强指针/强引用(iOS6及之前是retain) weak: 弱智真/弱引用(iOS6及之前是assign)   默认情况所有指针都是强指针 ...

随机推荐

  1. linux设备驱动归纳总结(六):2&period;分享中断号【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-90837.html xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  2. php使用位与运算符【&amp&semi;】位或运算符【&vert;】实现权限管理

    权限值是这样的2^0=1,相应2进数为”0001″(在这里^我表示成”次方”,即:2的0次方,下同)2^1=2,相应2进数为”0010″2^2=4,相应2进数为”0100″2^3=8,相应2进数为”1 ...

  3. MATERIALIZED VIEW

    Oracle的实体化视图提供了强大的功能,可以用在不同的环境中,实体化视图和表一样可以直接进行查询.实体化视图可以基于分区表,实体化视图本身也可以分区. 主要用于预先计算并保存表连接或聚集等耗时较多的 ...

  4. 【原创】shadowebdict开发日记:基于linux的简明英汉字典(二)

    全系列目录: [原创]shadowebdict开发日记:基于linux的简明英汉字典(一) [原创]shadowebdict开发日记:基于linux的简明英汉字典(二) [原创]shadowebdic ...

  5. thinkPHP 视图

    一.模板的使用        a.规则        模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[index].html(.tp ...

  6. js防抖和节流

    今天在网上看到的,里面的内容非常多.说下我自己的理解. 所谓的防抖就是利用延时器来使你的最后一次操作执行.而节流是利用时间差的办法,每一段时间执行一次.下面是我的代码: 这段代码是右侧的小滑块跟随页面 ...

  7. mysql 正则表达式问号

    MySQL 中,用正则表达式匹配?,需要使用两个转义字符   \\? 因使用一个被坑了很久.

  8. 【转载】JVM 学习——垃圾收集器与内存分配策略

    本文主要是对<深入理解java虚拟机 第二版>第三章部分做的总结,文章中大部分内容都来自这章内容,也是博客 JVM 学习的第二部分. 简述 说到垃圾收集(Garbage Collectio ...

  9. 「2017 山东一轮集训 Day5」字符串 (后缀自动机, 拓扑排序)

    /** 首先通过SAM求出每个串本质不同的子串 然后发现转移不好处理整体的本质不同 形如串A可能状态有a,b,ab,空,串B可能状态有b,空两种, 那么我们需要处理ab + 空 和 a + b的情况 ...

  10. 转:PHP获取浏览器类型及版本号

    function getBrowser(){ $agent=$_SERVER["HTTP_USER_AGENT"]; if(strpos($agent,'MSIE')!==fals ...