[iOS基础控件 - 6.9.1] 聊天界面Demo 代码
//
// 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
//
// 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
//
// 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 代码的更多相关文章
- [iOS基础控件 - 6.11.3] 私人通讯录Demo 控制器的数据传递、存储
A.需求 1.搭建一个"私人通讯录"Demo 2.模拟登陆界面 账号 密码 记住密码开关 自动登陆开关 登陆按钮 3.退出注销 4.增删改查 5.恢复数据(取消修改) 这个代码 ...
- [iOS基础控件 - 3.1] QQ登陆界面
A.storyboard 控件版 1.label 2.textfield a.Keyboard Type 账号:Number Pad 密码:Num ...
- [iOS基础控件 - 5.5] 代理设计模式 (基于”APP列表"练习)
A.概述 在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能 1.按钮点击后,显示为“已下载”,并且不 ...
- [iOS基础控件 - 6.9] 聊天界面Demo
A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话 ...
- iOS 基础控件(下)
上篇介绍了UIButton.UILabel.UIImageView和UITextField,这篇就简短一点介绍UIScrollView和UIAlertView. UIScrollView 顾名思义也知 ...
- [iOS基础控件 - 7.0] UIWebView
A.基本使用 1.概念 iOS内置的浏览器控件 Safari浏览器就是通过UIWebView实现的 2.用途:制作简易浏览器 (1)基本请求 创建请求 加载请求 (2)代理监听webView加载, ...
- [iOS基础控件 - 6.10.2] PickerView 自定义row内容 国家选择Demo
A.需求 1.自定义一个UIView和xib,包含国家名和国旗显示 2.学习row的重用 B.实现步骤 1.准备plist文件和国旗图片 2.创建模型 // // Flag.h // Co ...
- iOS基础 - 控件属性
一.控件的属性 1.CGRect frame 1> 表示控件的位置和尺寸(以父控件的左上角为坐标原点(0, 0)) 2> 修改这个属性,可以调整控件的位置和尺寸 2.CGPoint cen ...
- [iOS基础控件 - 6.12.3] @property属性 strong weak copy
A.概念 @property 的修饰词 strong: 强指针/强引用(iOS6及之前是retain) weak: 弱智真/弱引用(iOS6及之前是assign) 默认情况所有指针都是强指针 ...
随机推荐
- git stash 暂存当前修改
当我们在开发项目的时候,突然来一个变更需要修改,我们除了将当前项目提交(commit)后切换(checkout) 到其他分支外,我们还可以先将当前的修改暂存(stash)起来,然后再切换(checko ...
- UVa 11762 (期望 DP) Race to 1
设f(x)表示x转移到1需要的次数的期望,p(x)为不超过x的素数的个数,其中能整除x的有g(x)个 则有(1-g(x)/p(x))的概率下一步还是转移到x,剩下的情况各有1/p(x)的概率转移到x/ ...
- CodeForces Round #278 (Div.2) (待续)
A 这么简单的题直接贴代码好了. #include <cstdio> #include <cmath> using namespace std; bool islucky(in ...
- bzoj1934: [Shoi2007]Vote 善意的投票
最大流..建图方式都是玄学啊.. //Dinic是O(n2m)的. #include<cstdio> #include<cstring> #include<cctype& ...
- “main cannot be resolved or is not a field”解决方案
.layout.main总是在layout上有错误提示波浪线. 解决方法: (1) 删除"import android.R;". (2) 勾选上Eclipse中的"Pro ...
- codeforces 340A The Wall(简单数学题)
题意:输入a,b,x,y,a,b分别是两人的步数(每a块砖,刷一次),则有一些砖被两人同时刷到了,问[x,y]区间内有多少块砖同时被两人刷到. 分析:就是求[x,y]中有多少个能把a,b的最小公倍数l ...
- macro names must be identifiers
1.错把 #include 写成了 #define 会报这个错 2.定义一个不存在的宏业会报这个错,如加了-DANDRO 而ANDRO不存在
- I.MX6 Ubuntu core porting
/*********************************************************************** * I.MX6 Ubuntu core porting ...
- AngularJS 拦截器和应用例子(转)
$httpAngularJS 的 $http 服务允许我们通过发送 HTTP 请求方式与后台进行通信.在某些情况下,我们希望可以俘获所有的请求,并且在将其发送到服务端之前进行操作.还有一些情况是,我们 ...
- CXF之jaxws:endpoint对spring bean的引用
由于CXF对spring的无缝支持,CXF的使用,经常与spring捆绑在一起.随之而起的,自然是想在jaxws:endpoint中引用spring bean.在CXF提供的HelloWorld例子中 ...