首页 > 代码库 > [iOS基础控件 6.9.1] 聊天界面Demo 代码

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

框架:
Image(108)
 
所有代码文件
Image(118)
 
Model:
 1 // 2 //  Message.h 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8 // message信息模型,存储聊天记录 9 10 #import <Foundation/Foundation.h>11 12 typedef enum {13     MessageTypeMe = 0, // 我发出的信息14     MessageTypeOhter = 1 // 对方发出的信息15 } MessageType;16 17 @interface Message : NSObject18 19 /** 信息 */20 @property(nonatomic, copy) NSString *text;21 22 /** 发送时间 */23 @property(nonatomic, copy) NSString *time;24 25 /** 发送方 */26 @property(nonatomic, assign) MessageType type;27 28 /** 是否隐藏发送时间 */29 @property(nonatomic, assign) BOOL hideTime;30 31 - (instancetype) initWithDictionary:(NSDictionary *) dictionary;32 + (instancetype) messageWithDictionary:(NSDictionary *) dictionary;33 + (instancetype) message;34 35 @end
 
 1 // 2 //  Message.m 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import "Message.h"10 11 @implementation Message12 13 - (instancetype) initWithDictionary:(NSDictionary *) dictionary {14     if (self = [super init]) {15         [self setValuesForKeysWithDictionary:dictionary];16     }17    18     return self;19 }20 21 + (instancetype) messageWithDictionary:(NSDictionary *) dictionary {22     return [[self alloc] initWithDictionary:dictionary];23 }24 25 + (instancetype) message {26     return [self messageWithDictionary:nil];27 }28 29 @end
 
 1 // 2 //  MessageFrame.h 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8 // 存储每个cell内子控件的位置尺寸的frame 9 10 #import <Foundation/Foundation.h>11 #import <UIKit/UIKit.h>12 #import "Message.h"13 14 #define MESSAGE_TIME_FONT [UIFont systemFontOfSize:13]15 #define MESSAGE_TEXT_FONT [UIFont systemFontOfSize:15]16 #define TEXT_INSET 2017 18 @interface MessageFrame : NSObject19 20 /** 发送时间  */21 @property(nonatomic, assign, readonly) CGRect timeFrame;22 23 /** 头像 */24 @property(nonatomic, assign, readonly) CGRect iconFrame;25 26 /** 信息 */27 @property(nonatomic, assign, readonly) CGRect textFrame;28 29 /** 信息model */30 @property(nonatomic, strong) Message *message;31 32 /** cell的高度 */33 @property(nonatomic, assign) CGFloat cellHeight;34 35 36 @end
 
 1 // 2 //  MessageFrame.m 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import "MessageFrame.h"10 #import "NSString+Extension.h"11 12 @implementation MessageFrame13 14 /** 设置message,计算位置尺寸 */15 - (void)setMessage:(Message *)message {16     _message = message;17 18     // 间隙19     CGFloat padding = 10;20    21     // 1.发送时间22     if (NO == message.hideTime) {23         CGFloat timeWidth = [UIScreen mainScreen].bounds.size.width;24         CGFloat timeHeight = 40;25         CGFloat timeX = 0;26         CGFloat timeY = 0;27         _timeFrame = CGRectMake(timeX, timeY, timeWidth, timeHeight);28     }29    30     // 2.头像31     CGFloat iconWidth = 40;32     CGFloat iconHeight = 40;33    34     // 2.1 根据信息的发送方调整头像位置35     CGFloat iconX;36     if (MessageTypeMe == message.type) {37         // 我方,放在右边38         iconX = [UIScreen mainScreen].bounds.size.width - padding - iconWidth;39     } else {40         // 对方,放在左边41         iconX = padding;42     }43    44     CGFloat iconY = CGRectGetMaxY(_timeFrame) + padding;45     _iconFrame = CGRectMake(iconX, iconY, iconWidth, iconHeight);46    47     // 3.信息,尺寸可变48     CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;49     // 3.1 设置文本最大尺寸50     CGSize textMaxSize = CGSizeMake(screenWidth - iconWidth - padding * 10, MAXFLOAT);51     // 3.2 计算文本真实尺寸52     CGSize textRealSize = [message.text sizeWithFont:MESSAGE_TEXT_FONT maxSize:textMaxSize];53    54     // 3.3 按钮尺寸55     CGSize btnSize = CGSizeMake(textRealSize.width + TEXT_INSET*2, textRealSize.height + TEXT_INSET*2);56 57     // 3.4 调整信息的位置58     CGFloat textX;59     if (MessageTypeMe == message.type) {60         // 我方,放在靠右61         textX = CGRectGetMinX(_iconFrame) - btnSize.width - padding;62     } else {63         // 对方,放在靠左64         textX = CGRectGetMaxX(_iconFrame) + padding;65     }66    67     CGFloat textY = iconY;68     _textFrame = CGRectMake(textX, textY, btnSize.width, btnSize.height);69    70     // 4.cell的高度71     CGFloat iconMaxY = CGRectGetMaxY(_iconFrame);72     CGFloat textMaxY = CGRectGetMaxY(_textFrame);73     _cellHeight = MAX(iconMaxY, textMaxY) + padding;74 }75 76 77 @end
 
View:
 1 // 2 //  MessageCell.h 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import <UIKit/UIKit.h>10 11 #define BACKGROUD_COLOR [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1.0]12 13 @class MessageFrame, Message;14 15 @interface MessageCell : UITableViewCell16 17 /** 持有存储了聊天记录和聊天框位置尺寸的frame */18 @property(nonatomic, strong) MessageFrame *messageFrame;19 20 /** 传入父控件tableView引用的构造方法 */21 + (instancetype) cellWithTableView:(UITableView *) tableView;22 23 @end
 
  1 //  2 //  MessageCell.m  3 //  QQChatDemo  4 //  5 //  Created by hellovoidworld on 14/12/8.  6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved.  7 //  8   9 #import "MessageCell.h" 10 #import "MessageFrame.h" 11 #import "UIImage+Extension.h" 12  13 @interface MessageCell() 14  15 // 定义cell内的子控件,用于保存控件,然后进行数据和位置尺寸的计算 16 /** 发送时间 */ 17 @property(nonatomic, weak) UILabel *timeLabel; 18  19 /** 头像 */ 20 @property(nonatomic, weak) UIImageView *iconView; 21  22 /** 信息 */ 23 @property(nonatomic, weak) UIButton *textView; 24  25 @end 26  27 @implementation MessageCell 28  29 - (void)awakeFromNib { 30     // Initialization code 31 } 32  33 - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 34     [super setSelected:selected animated:animated]; 35  36     // Configure the view for the selected state 37 } 38  39 #pragma mark - 构造方法 40 // 自定义构造方法 41 + (instancetype) cellWithTableView:(UITableView *) tableView { 42     static NSString *ID = @"message"; 43     44     // 使用缓存池 45     MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 46     47     // 创建一个新的cell 48     if (nil == cell) { 49         cell = [[MessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; 50     } 51     52     return cell; 53 } 54  55 // 重写构造方法,创建cell中的各个子控件 56 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 57     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 58     59     // 设置cell的背景色 60     self.backgroundColor = BACKGROUD_COLOR; 61     62     // 1.发送时间 63     UILabel *timeLabel = [[UILabel alloc] init]; 64     [timeLabel setTextAlignment:NSTextAlignmentCenter]; 65     [timeLabel setFont:MESSAGE_TIME_FONT]; 66     [timeLabel setTextColor:[UIColor grayColor]]; 67     [self.contentView addSubview:timeLabel]; 68     self.timeLabel = timeLabel; 69     70     // 2.头像 71     UIImageView *iconView = [[UIImageView alloc] init]; 72     [self.contentView addSubview:iconView]; 73     self.iconView = iconView; 74     75     // 3.信息 76     UIButton *textView = [[UIButton alloc] init]; 77     [textView setTitle:@"text" forState:UIControlStateNormal]; 78     [textView.titleLabel setFont:MESSAGE_TEXT_FONT]; 79     80     // 3.1 如果是浅色背景,记得设置字体颜色,因为按钮的字体颜色默认是白色 81     [textView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 82     [textView.titleLabel setNumberOfLines:0]; // 设置自动换行 83     84     // 3.2 调整文字的内边距 85     textView.contentEdgeInsets = UIEdgeInsetsMake(TEXT_INSET, TEXT_INSET, TEXT_INSET, TEXT_INSET); 86     87     [self.contentView addSubview:textView]; 88     self.textView = textView; 89     90     return self; 91 } 92  93 #pragma mark - 加载数据 94 // 加载frame,初始化cell中子控件的数据、位置尺寸 95 - (void)setMessageFrame:(MessageFrame *) messageFrame { 96     _messageFrame = messageFrame; 97     98     // 1.发送时间 99     self.timeLabel.text = messageFrame.message.time;100     self.timeLabel.frame = messageFrame.timeFrame;101    102     // 2.头像103     NSString *icon = (messageFrame.message.type == MessageTypeMe)? @"me":@"other";104     self.iconView.image = [UIImage imageNamed:icon];105     self.iconView.frame = messageFrame.iconFrame;106    107     // 3.信息108     [self.textView setTitle:messageFrame.message.text forState:UIControlStateNormal];109     self.textView.frame = messageFrame.textFrame;110    111     // 3.1 设置聊天框112     NSString *chatImageNormalName;113     NSString *chatImageHighlightedName;114     if (MessageTypeMe == messageFrame.message.type) {115         chatImageNormalName = @"chat_send_nor";116         chatImageHighlightedName = @"chat_send_press_pic";117     } else {118         chatImageNormalName = @"chat_receive_nor";119         chatImageHighlightedName = @"chat_receive_press_pic";120     }121    122     UIImage *chatImageNormal = [UIImage resizableImage:chatImageNormalName];123     UIImage *chatImageHighlighted = [UIImage resizableImage:chatImageHighlightedName];124     [self.textView setBackgroundImage:chatImageNormal forState:UIControlStateNormal];125     [self.textView setBackgroundImage:chatImageHighlighted forState:UIControlStateHighlighted];126 }127 128 129 @end
 
Controller:
  1 //  2 //  ViewController.m  3 //  QQChatDemo  4 //  5 //  Created by hellovoidworld on 14/12/8.  6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved.  7 //  8   9 #import "ViewController.h" 10 #import "Message.h" 11 #import "MessageCell.h" 12 #import "MessageFrame.h" 13  14 @interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate> 15  16 /** 聊天区tableView */ 17 @property (weak, nonatomic) IBOutlet UITableView *tableView; 18  19 /** 信息记录数据 */ 20 @property(nonatomic, strong) NSMutableArray *messages; 21  22 /** 信息输入框 */ 23 @property (weak, nonatomic) IBOutlet UITextField *inputView; 24  25 @end 26  27 @implementation ViewController 28  29 - (void)viewDidLoad { 30     [super viewDidLoad]; 31     // Do any additional setup after loading the view, typically from a nib. 32     33     // 设置dataSource 34     self.tableView.dataSource = self; 35     36     // 设置tableView的delegate 37     self.tableView.delegate = self; 38     39     // 设置tableView背景色,当键盘呼出隐藏的时候,避免默认的黑色背景出现太突兀 40     self.tableView.backgroundColor = BACKGROUD_COLOR; 41     42     // 设置聊天区TableView 43     // 不使用分割线 44     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 45     // 禁止选中cell 46     [self.tableView setAllowsSelection:NO]; 47     48     // 设置虚拟键盘监听器 49     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; 50     51     // 设置TextField文字左间距 52     self.inputView.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)]; 53     self.inputView.leftViewMode = UITextFieldViewModeAlways; 54     55     // 设置信息输入框的代理 56     self.inputView.delegate = self; 57 } 58  59 - (void)didReceiveMemoryWarning { 60     [super didReceiveMemoryWarning]; 61     // Dispose of any resources that can be recreated. 62 } 63  64 - (BOOL)prefersStatusBarHidden { 65     return YES; 66 } 67  68 #pragma mark - 数据加载 69 /** 延迟加载plist文件数据 */ 70 - (NSMutableArray *)messages { 71     if (nil == _messages) { 72         NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"messages.plist" ofType:nil]]; 73         74         NSMutableArray *mdictArray = [NSMutableArray array]; 75         for (NSDictionary *dict in dictArray) { 76             Message *message = [Message messageWithDictionary:dict]; 77             78             // 判断是否发送时间与上一条信息的发送时间相同,若是则不用显示了 79             MessageFrame *lastMessageFrame = [mdictArray lastObject]; 80             if (lastMessageFrame && [message.time isEqualToString:lastMessageFrame.message.time]) { 81                 message.hideTime = YES; 82             } 83             84             MessageFrame *messageFrame = [[MessageFrame alloc] init]; 85             messageFrame.message = message; 86             [mdictArray addObject:messageFrame]; 87         } 88         89         _messages = mdictArray; 90     } 91     92     return _messages; 93 } 94  95 #pragma mark - dataSource方法 96 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 97     return  self.messages.count; 98 } 99 100 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {101     MessageCell *cell = [MessageCell cellWithTableView:self.tableView];102     cell.messageFrame = self.messages[indexPath.row];103    104     return cell;105 }106 107 108 #pragma mark - tableView代理方法109 /** 动态设置每个cell的高度 */110 - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {111     MessageFrame *messageFrame = self.messages[indexPath.row];112     return messageFrame.cellHeight;113 }114 115 #pragma mark - scrollView 代理方法116 /** 点击拖曳聊天区的时候,缩回键盘 */117 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {118     // 1.缩回键盘119     [self.view endEditing:YES];120 }121 122 123 #pragma mark - 监听事件124 - (void) keyboardWillChangeFrame:(NSNotification *) note {125     // 1.取得弹出后的键盘frame126     CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];127    128     // 2.键盘弹出的耗时时间129     CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];130    131     // 3.键盘变化时,view的位移,包括了上移/恢复下移132     CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height;133    134     [UIView animateWithDuration:duration animations:^{135         self.view.transform = CGAffineTransformMakeTranslation(0, transformY);136     }];137 }138 139 #pragma mark - TextField 代理方法140 /** 回车响应事件 */141 - (BOOL)textFieldShouldReturn:(UITextField *)textField {142     // 我方发出信息143     [self sendMessageWithContent:textField.text andType:MessageTypeMe];144    145     // 自动回复146     [self sendMessageWithContent:[NSString stringWithFormat:@"%@\n%@", textField.text, @"你妹!!!"] andType:MessageTypeOhter];147    148     // 消除消息框内容149     self.inputView.text = nil;150    151     [self.tableView reloadData];152    153     // 滚动到最新的消息154     NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:self.messages.count - 1 inSection:0];155     [self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];156    157     return YES; // 返回值意义不明158 }159 160 // 发送消息161 - (void) sendMessageWithContent:(NSString *) text andType:(MessageType) type {162     // 获取当前时间163     NSDate *date = [NSDate date];164     NSDateFormatter *formatter = [[NSDateFormatter alloc] init];165     formatter.dateFormat = @"yyyy-MMM-dd hh:mm:ss";166     NSString *dateStr = [formatter stringFromDate:date];167    168     // 我方发出信息169     NSDictionary *dict = @{@"text":text,170                            @"time":dateStr,171                            @"type":[NSString stringWithFormat:@"%d", type]};172    173     Message *message = [[Message alloc] init];174     [message setValuesForKeysWithDictionary:dict];175     MessageFrame *messageFrame = [[MessageFrame alloc] init];176     messageFrame.message = message;177    178     [self.messages addObject:messageFrame];179 }180 181 @end182  

 

工具类:
 1 // 2 //  NSString+Extension.h 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8 // NSString扩展类 9 10 #import <Foundation/Foundation.h>11 #import <UIKit/UIKit.h>12 13 @interface NSString (Extension)14 15 /** 测量文本的尺寸 */16 - (CGSize) sizeWithFont:(UIFont *)font maxSize:(CGSize) maxSize;17 18 @end
 
 1 // 2 //  NSString+Extension.m 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import "NSString+Extension.h"10 11 @implementation NSString (Extension)12 13 /** 测量文本的尺寸 */14 - (CGSize)sizeWithFont:(UIFont *)font maxSize:(CGSize)maxSize {15     NSDictionary *attrs = @{NSFontAttributeName: font};16     CGSize size =  [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;17    18     return size;19 }20 21 @end
 
 1 // 2 //  UIImage+Extension.h 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8 // NSImage 类的扩展 9 10 #import <Foundation/Foundation.h>11 #import <UIKit/UIKit.h>12 13 @interface UIImage (Extension)14 15 + (UIImage *) resizableImage:(NSString *) imageName;16 17 @end18  

 

 1 // 2 //  UIImage+Extension.m 3 //  QQChatDemo 4 // 5 //  Created by hellovoidworld on 14/12/8. 6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved. 7 // 8  9 #import "UIImage+Extension.h"10 11 @implementation UIImage (Extension)12 13 + (UIImage *) resizableImage:(NSString *) imageName {14     UIImage *image = [UIImage imageNamed:imageName];15     // 取图片中部的1 x 1进行拉伸16     UIEdgeInsets insets = UIEdgeInsetsMake(image.size.height/2, image.size.width/2, image.size.height/2 + 1, image.size.width/2 + 1);17     return [image resizableImageWithCapInsets:insets];18 }19 20 @end

 

 
 

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