iOS 聊天界面

                                        

1 #import <UIKit/UIKit.h>
2 
3 @interface AppDelegate : UIResponder <UIApplicationDelegate>
4 
5 @property (strong, nonatomic) UIWindow *window;
6 
7 
8 @end
 1 #import "AppDelegate.h"
 2 #import "YXYCViewController.h"
 3 @interface AppDelegate ()
 4 
 5 @end
 6 
 7 @implementation AppDelegate
 8 
 9 
10 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
11     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
12     // Override point for customization after application launch.
13     self.window.backgroundColor = [UIColor whiteColor];
14     
15     self.window.rootViewController = [[YXYCViewController alloc] init];
16     
17     [self.window makeKeyAndVisible];
18     return YES;
19 }
20 
21 @end
1 #import <UIKit/UIKit.h>
2 
3 @interface YXYCViewController : UIViewController
4 
5 @end
  1 #import "YXYCViewController.h"
  2 #import "YXYCChatUser.h"
  3 #import "YXYCChatTableViewDataSource.h"
  4 #import <QuartzCore/QuartzCore.h>
  5 #import "YXYCChatTableView.h"
  6 #import "YXYCChatData.h"
  7 #define lineHeight 16.0f
  8 #define scale [UIScreen mainScreen].bounds.size.width/320.0
  9 @interface YXYCViewController ()<YXYCChatTableViewDataSource,UITextViewDelegate>
 10 {
 11     UIView *textInputView;
 12     UITextField *textField;
 13     NSMutableArray *Chats;
 14     
 15     UIView *sendView;
 16     UIButton *sendButton;
 17     UITextView *msgText;
 18     BOOL composing;
 19     float prevLines;
 20     YXYCChatUser *me;
 21     YXYCChatUser *you;
 22     //键盘的高度
 23     float keyboardHeight;
 24 }
 25 @property (strong, nonatomic) YXYCChatTableView *chatTable;
 26 @end
 27 
 28 @implementation YXYCViewController
 29 
 30 CGRect appFrame;
 31 - (void)viewDidLoad {
 32     [super viewDidLoad];
 33     // 添加监听
 34     [self addNotification];
 35     // 设置背景颜色
 36     self.view.backgroundColor = [UIColor lightGrayColor];
 37     // 初始化tableView
 38     [self setupTableView];
 39     // 初始化view和textView
 40     [self setupUIViewAndUITextView];
 41     // 初始化sendButton
 42     [self setupSendButton];
 43     // 加载数据
 44     [self loadData];
 45     
 46 }
 47 // 初始化YXYCChatTableView
 48 - (void)setupTableView
 49 {
 50     appFrame = [[UIScreen mainScreen] bounds];
 51     // 创建一个self.chatTable(YXYCChatTableView类型)
 52     self.chatTable = [[YXYCChatTableView alloc] initWithFrame:CGRectMake(0, 40, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height - 40) style:UITableViewStylePlain];
 53     // 设置self.chatTable的背景颜色
 54     self.chatTable.backgroundColor = [UIColor whiteColor];
 55     [self.view addSubview:self.chatTable];
 56 }
 57 // 初始化sendView和msgText
 58 - (void)setupUIViewAndUITextView
 59 {
 60     // 初始化sendView
 61     sendView = [[UIView alloc] initWithFrame:CGRectMake(0, appFrame.size.height-56, appFrame.size.width, 56)];
 62     sendView.backgroundColor = [UIColor blueColor];
 63     sendView.alpha = 0.9;
 64     // 初始化msgText
 65     msgText = [[UITextView alloc] initWithFrame:CGRectMake(7, 10, 225*scale, 36)];
 66     msgText.backgroundColor = [UIColor whiteColor];
 67     msgText.textColor = [UIColor blackColor];
 68     msgText.font = [UIFont boldSystemFontOfSize:12];
 69     // 自动调整与父视图的位置 UIViewAutoresizingFlexibleHeight 自动调整自己的高度,保证与superView顶部和底部的距离不变;UIViewAutoresizingFlexibleTopMargin 自动调整与superView顶部的距离,保证与superView底部的距离不变。
 70     msgText.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
 71     // 设置圆角半径
 72     msgText.layer.cornerRadius = 10.0f;
 73     // 设置键盘返回键的类型
 74     msgText.returnKeyType = UIReturnKeySend;
 75     msgText.showsHorizontalScrollIndicator = NO;
 76     msgText.showsVerticalScrollIndicator = NO;
 77     // 设置UITextView代理
 78     msgText.delegate = self;
 79     [sendView addSubview:msgText];
 80     msgText.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
 81     [self.view addSubview:sendView];
 82 }
 83 // 初始化sendButton
 84 - (void)setupSendButton
 85 {
 86     sendButton = [[UIButton alloc] initWithFrame:CGRectMake(235*scale, 10, 77, 36)];
 87     sendButton.backgroundColor = [UIColor lightGrayColor];
 88     [sendButton addTarget:self action:@selector(sendMessage) forControlEvents:UIControlEventTouchUpInside];
 89     // 自动调整与父视图的位置
 90     sendButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
 91     sendButton.layer.cornerRadius = 6.0f;
 92     [sendButton setTitle:@"Send" forState:UIControlStateNormal];
 93     [sendView addSubview:sendButton];
 94 }
 95 // 加载数据
 96 - (void)loadData
 97 {
 98     // 创建两个YXYCChatUser对象
 99     me = [[YXYCChatUser alloc] initWithUsername:@"Peter" avatarImage:[UIImage imageNamed:@"me.png"]];
100     you = [[YXYCChatUser alloc] initWithUsername:@"You" avatarImage:[UIImage imageNamed:@"noavatar.png"]];
101     //创建几个YXYCChatData对象
102     YXYCChatData *first = [YXYCChatData dataWithText:@"Hey,how are you doing? I'm in Paris take a look at this picture." date:[NSDate dateWithTimeIntervalSinceNow:-600] type:ChatTypeMine andUser:me];
103     YXYCChatData *second = [YXYCChatData dataWithImage:[UIImage imageNamed:@"eiffeltower.jpg"] date:[NSDate dateWithTimeIntervalSinceNow:-290] type:ChatTypeMine andUser:me];
104     YXYCChatData *third = [YXYCChatData dataWithText:@"Wow..Really cool picture out there. Wish I could be with you" date:[NSDate dateWithTimeIntervalSinceNow:-5] type:ChatTypeSomeone andUser:you];
105     YXYCChatData *forth = [YXYCChatData dataWithText:@"Maybe next time you can come with me." date:[NSDate dateWithTimeIntervalSinceNow:+0] type:ChatTypeMine andUser:me];
106     // 通过YXYCChatData对象来初始化Chats(数组)
107     Chats = [[NSMutableArray alloc] initWithObjects:first,second,third,forth, nil];
108     // 确认YXYCChatTableViewDataSource的代理
109     self.chatTable.chatDataSource = self;
110     // 调用reloadData方法(此方法已被重写)
111     [self.chatTable reloadData];
112 }
113 // 页面消失时移除监听
114 - (void)viewDidDisappear:(BOOL)animated
115 {
116     [self removeNotification];
117 }
118 
119 - (void)sendMessage
120 {
121     composing = NO;
122     YXYCChatData *thisChat = [YXYCChatData dataWithText:msgText.text date:[NSDate date] type:ChatTypeMine andUser:me];
123     [Chats addObject:thisChat];
124     [self.chatTable reloadData];
125     [self showTableView];
126     // 注销msgText为第一响应者
127     [msgText resignFirstResponder];
128     // 清除原来的文本内容
129     msgText.text = @"";
130     sendView.frame = CGRectMake(0, appFrame.size.height - 56, 320*scale, 56);
131     // TODO:注意
132     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[Chats count] inSection:0];
133     // tableView 滚到底部
134     [self.chatTable scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
135 }
136 
137 #pragma mark -UITextViewDelegat-
138 //如果用户按回车键,则认为结束编辑,并进行发送消息
139 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
140 {
141     if ([text isEqualToString:@"
"]) {
142         [self sendMessage];
143         return NO;
144     }
145     return YES;
146 }
147 
148 /**
149  *  @return 返回输入文本在UITextView上的高度
150  */
151 - (CGFloat)textY
152 {
153     // 设置字体的样式和大小
154     UIFont *systemFont = [UIFont boldSystemFontOfSize:12];
155     int width = 225.0, heigth = 10000.0;
156     NSMutableDictionary *atts = [[NSMutableDictionary alloc] init];
157     [atts setObject:systemFont forKey:NSFontAttributeName];
158     // 根据文字量返回CGRect
159     CGRect size = [msgText.text boundingRectWithSize:CGSizeMake(width, heigth) options:NSStringDrawingUsesLineFragmentOrigin attributes:atts context:nil];
160     //获取文字的高度
161     float textHeight = size.size.height;
162 
163     float lines = textHeight / lineHeight;
164     if (lines >= 4) {
165         lines = 4;
166     }
167     if ([msgText.text length] == 0) {
168         lines = 0.9375f;
169     }
170     return 190 - (lines * lineHeight) + lineHeight;
171 }
172 // 输入文字时,重新计算和布置sendView的frame,并保持在键盘上方
173 - (void)textViewDidChange:(UITextView *)textView
174 {
175     // 设置文字的样式和大小
176     UIFont *systemFont = [UIFont boldSystemFontOfSize:12];
177     int width = 225.0, height = 10000.0;
178     NSMutableDictionary *atts = [[NSMutableDictionary alloc] init];
179     [atts setObject:systemFont forKey:NSFontAttributeName];
180     
181     CGRect size = [msgText.text boundingRectWithSize:CGSizeMake(width, height) options:NSStringDrawingUsesLineFragmentOrigin attributes:atts context:nil];
182     float textHeight = size.size.height;
183     float lines = textHeight / lineHeight;
184     if (lines > 4) {
185         lines = 4;
186     }
187     
188     composing = YES;
189     msgText.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
190     sendView.frame = CGRectMake(0, appFrame.size.height - keyboardHeight - 56 - (lines * lineHeight) + lineHeight, appFrame.size.width, 56 + (lines * lineHeight) - lineHeight);
191     
192     if (prevLines != lines) {
193         [self shortenTableView];
194     }
195     prevLines = lines;
196 }
197 
198 // let's change the frame of the chatTable so we can see the bottom
199 - (void)shortenTableView
200 {
201     [UIView beginAnimations:@"moveView" context:nil];
202     [UIView setAnimationDuration:0.1];
203     self.chatTable.frame = CGRectMake(0, 40, appFrame.size.width, appFrame.size.height - keyboardHeight- 56 - 40 );
204     [UIView commitAnimations];
205     prevLines = 1;
206 }
207 
208 // show the chatTable as it was
209 - (void)showTableView
210 {
211     [UIView beginAnimations:@"moveView" context:nil];
212     [UIView setAnimationDuration:0.1];
213     self.chatTable.frame = CGRectMake(0, 40, appFrame.size.width, appFrame.size.height - 56 - 40);
214     [UIView commitAnimations];
215 }
216 
217 // when users starts typing change the frame position and shorten the chatTable
218 - (void)textViewDidBeginEditing:(UITextView *)textView
219 {
220     [UIView beginAnimations:@"moveView" context:nil];
221     [UIView setAnimationDuration:0.3];
222     sendView.frame = CGRectMake(0, appFrame.size.height - keyboardHeight - 56, appFrame.size.width, 56);
223     [UIView commitAnimations];
224     [self shortenTableView];
225     // 变成第一响应者
226     [msgText becomeFirstResponder];
227 }
228 
229 - (void)addNotification
230 {
231     //键盘出现通知
232     [[NSNotificationCenter defaultCenter] addObserver:self
233                                              selector:@selector(handleKeyBoardShow:)
234                                                  name:UIKeyboardWillShowNotification object:nil];
235 }
236 #pragma mark - keyboard delegate
237 -(void)handleKeyBoardShow:(NSNotification*)notify
238 {
239     NSDictionary *info = [notify userInfo];
240     // 获取键盘的尺寸
241     CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
242     //获取键盘的高度
243     keyboardHeight = keyboardSize.height;
244 }
245 // 移除监听
246 -(void)removeNotification
247 {
248     [[NSNotificationCenter defaultCenter] removeObserver:self];
249 }
250 
251 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
252 {
253     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
254 }
255 
256 
257 #pragma mark - YXYCChatTableView implementation
258 // here are the required implementation from your YXYCChatTableViewDataSource
259 - (NSInteger)rowsForChatTable:(YXYCChatTableView *)tableView
260 {
261     return [Chats count];
262 }
263 
264 - (YXYCChatData *)chatTableView:(YXYCChatTableView *)tableView dataForRow:(NSInteger)row
265 {
266     return [Chats objectAtIndex:row];
267 }
268 
269 - (void)didReceiveMemoryWarning {
270     [super didReceiveMemoryWarning];
271     
272 }
273 
274 
275 @end
 1 #import <Foundation/Foundation.h>
 2 
 3 @class YXYCChatData;
 4 @class YXYCChatTableView;
 5 @protocol YXYCChatTableViewDataSource <NSObject>
 6 
 7 - (NSInteger)rowsForChatTable:(YXYCChatTableView *)tableView;
 8 - (YXYCChatData *)chatTableView:(YXYCChatTableView *)tableView dataForRow:(NSInteger)row;
 9 
10 @end
 1 #import <Foundation/Foundation.h>
 2 #import <UIKit/UIKit.h>
 3 @class YXYCChatUser;
 4 //枚举(聊天类型)
 5 typedef enum _YXYCChatType
 6 {
 7     ChatTypeMine = 0,
 8     ChatTypeSomeone = 1
 9 } YXYCChatType;
10 
11 @interface YXYCChatData : NSObject
12 /**
13  *  聊天的对象类型
14  */
15 @property (readonly, nonatomic) YXYCChatType type;
16 /**
17  *  日期
18  */
19 @property (readonly, nonatomic, strong) NSDate *date;
20 @property (readonly, nonatomic, strong) UIView *view;
21 @property (readonly, nonatomic) UIEdgeInsets insets;
22 /**
23  *  聊天的用户
24  */
25 @property (nonatomic, strong) YXYCChatUser *chatUser;
26 
27 // 自定义初始化
28 + (id)dataWithText:(NSString *)text date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user;
29 
30 + (id)dataWithImage:(UIImage *)image date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user;
31 
32 + (id)dataWithView:(UIView *)view date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user insets:(UIEdgeInsets)insets;
33 
34 @end
  1 #import "YXYCChatData.h"
  2 #import <QuartzCore/QuartzCore.h>
  3 
  4 @implementation YXYCChatData
  5 
  6 //设置一些文本和图片的常量
  7 const UIEdgeInsets textInsetsMine = {5, 10, 11, 17};
  8 const UIEdgeInsets textInsetsSomeone = {5, 15, 11, 10};
  9 const UIEdgeInsets imageInsetsMine = {11, 13, 16, 22};
 10 const UIEdgeInsets imageInsetsSomeone = {11, 18, 16, 14};
 11 
 12 #pragma mark initializers
 13 + (id)dataWithText:(NSString *)text date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user
 14 {
 15     return [[YXYCChatData alloc] initWithText:text date:date type:type andUser:_user];
 16 }
 17 /**
 18  *  初始化
 19  *
 20  *  @param text  内容
 21  *  @param date  日期
 22  *  @param type  聊天对象类型
 23  *  @param _user 用户
 24  *
 25  *  @return YXYCChatData对象
 26  */
 27 - (id)initWithText:(NSString *)text date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user
 28 {
 29     // 设置字体
 30     UIFont *font = [UIFont boldSystemFontOfSize:12];
 31     // 文本显示的宽,以及最大的高度
 32     int width = 225 , height = 10000.0;
 33     NSMutableDictionary *atts = [[NSMutableDictionary alloc] init];
 34     [atts setObject:font forKey:NSFontAttributeName];
 35     // 根据文本内容返回CGRect
 36     CGRect size = [text boundingRectWithSize:CGSizeMake(width, height) options:NSStringDrawingUsesLineFragmentOrigin attributes:atts context:nil];
 37     // 根据返回的尺寸初始化Label
 38     UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, size.size.width, size.size.height)];
 39     // 可多行输入
 40     label.numberOfLines = 0;
 41     // 以单词为单位换行,以单位为单位截断
 42     label.lineBreakMode = NSLineBreakByWordWrapping;
 43     // text参数若存在,Label则显示text的内容;否则Label不显示文本内容
 44     label.text = (text ? text : @"");
 45     label.font = font;
 46     label.backgroundColor = [UIColor clearColor];
 47     UIEdgeInsets insets = (type == ChatTypeMine ? textInsetsMine : textInsetsSomeone);
 48     return [self initWithView:label date:date type:type andUser:_user insets:insets];
 49 }
 50 
 51 + (id)dataWithImage:(UIImage *)image date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user
 52 {
 53     return [[YXYCChatData alloc] initWithImage:image date:date type:type andUser:_user];
 54 }
 55 /**
 56  *  初始化
 57  *
 58  *  @param image 图片
 59  *  @param date  日期
 60  *  @param type  聊天对象的类型
 61  *  @param _user 用户
 62  *
 63  *  @return YXYCChatData对象类型
 64  */
 65 - (id)initWithImage:(UIImage *)image date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user
 66 {
 67     // 获取图片的尺寸
 68     CGSize size = image.size;
 69     // 如果图片的宽大于220,size的宽就等于220,size的高度等于原来的高度与原来的宽度的比例乘以220
 70     if (size.width > 220) {
 71         size.height /= (size.width/220);
 72         size.width = 220;
 73     }
 74     // 根据size的大小初始化imageView
 75     UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
 76     imageView.image = image;
 77     //设置imageView的圆角半径
 78     imageView.layer.cornerRadius = 5.0;
 79     imageView.layer.masksToBounds = YES;
 80     UIEdgeInsets insets = (type == ChatTypeMine ? imageInsetsMine : imageInsetsSomeone);
 81     return [self initWithView:imageView date:date type:type andUser:_user insets:insets];
 82 }
 83 
 84 + (id)dataWithView:(UIView *)view date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user insets:(UIEdgeInsets)insets
 85 {
 86     return [[YXYCChatData alloc] initWithView:view date:date type:type andUser:(YXYCChatUser *)_user insets:insets];
 87 }
 88 /**
 89  *  初始化
 90  *
 91  *  @param view   view
 92  *  @param date   日期
 93  *  @param type   聊天对象的类型
 94  *  @param _user  用户
 95  *  @param insets
 96  *
 97  *  @return YXYCChatData对象类型
 98  */
 99 - (id)initWithView:(UIView *)view date:(NSDate *)date type:(YXYCChatType)type andUser:(YXYCChatUser *)_user insets:(UIEdgeInsets)insets
100 {
101     self = [super init];
102     if (self) {
103         _chatUser = _user;
104         _view = view;
105         _date = date;
106         _type = type;
107         _insets = insets;
108     }
109     return self;
110 }
111 
112 @end
 1 #import <UIKit/UIKit.h>
 2 
 3 @interface YXYCChatHeaderTableViewCell : UITableViewCell
 4 /**
 5  *  日期
 6  */
 7 @property (nonatomic, strong) NSDate *date;
 8 + (CGFloat)height;
 9 
10 @end
 1 #import "YXYCChatHeaderTableViewCell.h"
 2 
 3 @interface  YXYCChatHeaderTableViewCell()
 4 
 5 @property (nonatomic, retain) UILabel *label;
 6 
 7 @end
 8 
 9 @implementation YXYCChatHeaderTableViewCell
10 
11 + (CGFloat)height
12 {
13     return 30.0;
14 }
15 /**
16  *  设置时间,并把时间显示在YXYCChatHeaderTableViewCell上
17  */
18 - (void)setDate:(NSDate *)value
19 {
20     // 初始化dateFormatter
21     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
22     // 设置日期显示的方式
23     [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
24     // 设置时间显示的方式
25     [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
26     NSString *text = [dateFormatter stringFromDate:value];
27     
28     if (self.label) {
29         self.label.text = text;
30         return;
31     }
32     self.selectionStyle = UITableViewCellSelectionStyleNone;
33     // 初始化UILabel
34     self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, [YXYCChatHeaderTableViewCell height])];
35     //设置Label的文本内容
36     self.label.text = text;
37     // 设置Label文本字体的大小
38     self.label.font = [UIFont boldSystemFontOfSize:12];
39     // Label文本居中
40     self.label.textAlignment = NSTextAlignmentCenter;
41     // 设置Label文字的阴影偏余量
42     self.label.shadowOffset = CGSizeMake(0, 1);
43     // 设置Label文字阴影的颜色
44     self.label.shadowColor = [UIColor whiteColor];
45     // 设置Label文件的颜色
46     self.label.textColor = [UIColor darkGrayColor];
47     // 设置Label的背景颜色
48     self.label.backgroundColor = [UIColor clearColor];
49     [self addSubview:self.label];
50 }
51 
52 - (void)awakeFromNib {
53     // Initialization code
54 }
55 
56 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
57     [super setSelected:selected animated:animated];
58 
59     // Configure the view for the selected state
60 }
61 
62 @end
 1 #import <Foundation/Foundation.h>
 2 #import <UIKit/UIKit.h>
 3 @interface YXYCChatUser : NSObject
 4 /**
 5  *  用户名字
 6  */
 7 @property (nonatomic, strong) NSString *username;
 8 /**
 9  *  头像
10  */
11 @property (nonatomic, strong) UIImage *avatar;
12 /**
13  *  初始化
14  *
15  *  @param user  用户
16  *  @param image 头像
17  *
18  *  @return 返回id类型
19  */
20 - (id)initWithUsername:(NSString *)user avatarImage:(UIImage *)image;
21 
22 @end
 1 #import "YXYCChatUser.h"
 2 
 3 @implementation YXYCChatUser
 4 
 5 @synthesize avatar;
 6 @synthesize username;
 7 
 8 - (id)initWithUsername:(NSString *)user avatarImage:(UIImage *)image
 9 {
10     self = [super init];
11     if (self) {
12         self.avatar = [image copy];
13         self.username = [user copy];
14     }
15     return self;
16 }
17 
18 @end
 1 #import <UIKit/UIKit.h>
 2 #import "YXYCChatData.h"
 3 
 4 @interface YXYCChatTableViewCell : UITableViewCell
 5 /**
 6  *  日期
 7  */
 8 @property (nonatomic, strong) YXYCChatData *data;
 9 /**
10  *  设置日期
11  */
12 - (void)setData:(YXYCChatData *)data;
13 
14 @end
  1 #import "YXYCChatTableViewCell.h"
  2 #import "YXYCChatData.h"
  3 #import <QuartzCore/QuartzCore.h>
  4 #import "YXYCChatUser.h"
  5 
  6 @interface YXYCChatTableViewCell ()
  7 
  8 @property (nonatomic, retain) UIView *customView;
  9 @property (nonatomic, retain) UIImageView *bubbleImage;
 10 /**
 11  *  头像
 12  */
 13 @property (nonatomic, retain) UIImageView *avatarImage;
 14 
 15 //- (void)setupInternalData;
 16 
 17 @end
 18 
 19 @implementation YXYCChatTableViewCell
 20 
 21 @synthesize data = _data;
 22 
 23 - (void)setData:(YXYCChatData *)data
 24 {
 25     _data = data;
 26     [self rebuildUserInterface];
 27 }
 28 
 29 - (void)rebuildUserInterface
 30 {
 31     self.selectionStyle = UITableViewCellSelectionStyleNone;
 32     // 如果bubbleImage为空,则创建
 33     if (!self.bubbleImage) {
 34         self.bubbleImage = [[UIImageView alloc] init];
 35         [self addSubview:self.bubbleImage];
 36     }
 37     YXYCChatType type = self.data.type;
 38     CGFloat width = self.data.view.frame.size.width;
 39     CGFloat height = self.data.view.frame.size.height;
 40     CGFloat x = (type == ChatTypeSomeone) ? 0 : self.frame.size.width - width - self.data.insets.left - self.data.insets.right;
 41     CGFloat y = 0;
 42     // 如果用户有头像,则显示头像
 43     if (self.data.chatUser) {
 44         YXYCChatUser *thisUser = self.data.chatUser;
 45         [self.avatarImage removeFromSuperview];
 46         self.avatarImage = [[UIImageView alloc] initWithImage:(thisUser.avatar ? thisUser.avatar : [UIImage imageNamed:@"noavatar.png"])];
 47         self.avatarImage.layer.cornerRadius = 9.0;
 48         self.avatarImage.layer.masksToBounds = YES;
 49         // 设置avatarImage的边框颜色
 50         self.avatarImage.layer.borderColor = [UIColor colorWithWhite:0.0 alpha:0.2].CGColor;
 51         // 设置avatarImage边框的粗细
 52         self.avatarImage.layer.borderWidth = 1.0;
 53         // 计算x的位置
 54         CGFloat avatarX = (type == ChatTypeSomeone) ? 2 : self.frame.size.width - 52;
 55         CGFloat avatarY = self.frame.size.height - 50;
 56         //设计frame
 57         self.avatarImage.frame = CGRectMake(avatarX, avatarY, 50, 50);
 58         [self addSubview:self.avatarImage];
 59         CGFloat delta = self.frame.size.height - (self.data.insets.top + self.data.insets.bottom + self.data.view.frame.size.height);
 60         if (delta > 0) y = delta;
 61         if (type == ChatTypeSomeone) x += 54;
 62         if (type == ChatTypeMine) x -= 54;
 63     }
 64     [self.customView removeFromSuperview];
 65     self.customView = self.data.view;
 66     self.customView.frame = CGRectMake(x + self.data.insets.left, y + self.data.insets.top, width, height);
 67     [self.contentView addSubview:self.customView];
 68     //
 69     if (type == ChatTypeSomeone) {
 70         //创建一个内容可拉伸,而边角不拉伸的图片,需要两个参数,第一个是左边不拉伸区域的宽度,第二个参数是上面不拉伸的高度。
 71         self.bubbleImage.image = [[UIImage imageNamed:@"yoububble.png"] stretchableImageWithLeftCapWidth:21 topCapHeight:14];
 72     }else{
 73         self.bubbleImage.image = [[UIImage imageNamed:@"mebubble.png"] stretchableImageWithLeftCapWidth:15 topCapHeight:14];
 74     }
 75     self.bubbleImage.frame = CGRectMake(x, y, width + self.data.insets.left + self.data.insets.right, height + self.data.insets.top + self.data.insets.bottom);
 76 }
 77 
 78 //- (void)setUP:(YXYCChatData *)value
 79 //{
 80 //    self.data = value;
 81 //    [self rebuildUserInterface];
 82 //}
 83 
 84 - (void)setFrame:(CGRect)frame
 85 {
 86     [super setFrame:frame];
 87     [self rebuildUserInterface];
 88 }
 89 
 90 - (void)awakeFromNib {
 91     // Initialization code
 92 }
 93 
 94 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
 95     [super setSelected:selected animated:animated];
 96 
 97     // Configure the view for the selected state
 98 }
 99 
100 @end
 1 #import <UIKit/UIKit.h>
 2 #import "YXYCChatTableViewDataSource.h"
 3 #import "YXYCChatTableViewCell.h"
 4 
 5 typedef enum _ChatBubbleTypingType
 6 {
 7     ChatBubbleTypingTypeNobody = 0,
 8     ChatBubbleTypingTypeMe = 1,
 9     ChatBubbleTypingTypeSomebody = 2
10 } ChatBubbleTypingType;
11 
12 @interface YXYCChatTableView : UITableView
13 /**
14  *  添加代理
15  */
16 @property (nonatomic, assign) id<YXYCChatTableViewDataSource> chatDataSource;
17 /**
18  *  时间间隔
19  */
20 @property (nonatomic) NSTimeInterval snapInterval;
21 @property (nonatomic) ChatBubbleTypingType typingBubble;
22 
23 @end
  1 #import "YXYCChatTableView.h"
  2 #import "YXYCChatData.h"
  3 #import "YXYCChatHeaderTableViewCell.h"
  4 
  5 @interface YXYCChatTableView ()<UITableViewDelegate,UITableViewDataSource>
  6 
  7 @property (nonatomic, strong) NSMutableArray *bubbleSection;
  8 
  9 @end
 10 
 11 @implementation YXYCChatTableView
 12 
 13 - (id)init
 14 {
 15     self = [super init];
 16     if (self) [self initializer];
 17     return self;
 18 }
 19 
 20 - (void)initializer
 21 {
 22     self.backgroundColor = [UIColor clearColor];
 23     // 隐藏cell与cell之间的分离线
 24     self.separatorStyle = UITableViewCellSeparatorStyleNone;
 25     // 设置代理
 26     self.delegate = self;
 27     self.dataSource = self;
 28     self.snapInterval = 60 * 60 * 24;//一天的时间
 29     self.typingBubble = ChatBubbleTypingTypeNobody;
 30 }
 31 
 32 - (id)initWithFrame:(CGRect)frame
 33 {
 34     self = [super initWithFrame:frame];
 35     if (self) [self initializer];
 36     return self;
 37 }
 38 
 39 - (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
 40 {
 41     self = [super initWithFrame:frame style:UITableViewStylePlain];
 42     if (self) {
 43         [self initializer];
 44     }
 45     return self;
 46 }
 47 
 48 #pragma mark - 重写tableView的部分方法-
 49 - (void)reloadData
 50 {
 51     self.showsHorizontalScrollIndicator = NO;
 52     self.showsVerticalScrollIndicator = NO;
 53     self.bubbleSection = nil;
 54     int count = 0;
 55     self.bubbleSection = [[NSMutableArray alloc] init];
 56     if (self.chatDataSource && (count = (int)[self.chatDataSource rowsForChatTable:self]) > 0) {
 57         NSMutableArray *bubbleData = [[NSMutableArray alloc] initWithCapacity:count];
 58         for (int i = 0; i < count; i++) {
 59             NSObject *object = [self.chatDataSource chatTableView:self dataForRow:i];
 60             assert([object isKindOfClass:[YXYCChatData class]]);
 61             [bubbleData addObject:object];
 62         }
 63         // 根据时间进行排列
 64         [bubbleData sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
 65             YXYCChatData *bubbleData1 = (YXYCChatData *)obj1;
 66             YXYCChatData *bubbleData2 = (YXYCChatData *)obj2;
 67             return [bubbleData1.date compare:bubbleData2.date];
 68         }];
 69         // 以GMT时间的偏移秒数来初始化
 70         NSDate *last = [NSDate dateWithTimeIntervalSince1970:0];
 71         NSMutableArray *currentSection = nil;
 72         for (int i = 0; i < count; i++) {
 73             YXYCChatData *data = (YXYCChatData *)[bubbleData objectAtIndex:i];
 74             // 如果时间大于一天的时间就存入self.bubbleSection(用于分区)
 75             if ([data.date timeIntervalSinceDate:last] > self.snapInterval) {
 76                 currentSection = [[NSMutableArray alloc] init];
 77                 [self.bubbleSection addObject:currentSection];
 78             }
 79             [currentSection addObject:data];
 80             last = data.date;
 81         }
 82     }
 83     [super reloadData];
 84 }
 85 
 86 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 87 {
 88     int result = (int)[self.bubbleSection count];
 89     if (self.typingBubble != ChatBubbleTypingTypeNobody) {
 90         result ++;
 91     }
 92     return result;
 93 }
 94 
 95 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 96 {
 97     if (section >= [self.bubbleSection count]) {
 98         return 1;
 99     }
100     return [[self.bubbleSection objectAtIndex:section] count] + 1;
101 }
102 
103 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
104 {
105     // Header
106     if (indexPath.row == 0) {
107         return [YXYCChatHeaderTableViewCell height];
108     }
109     YXYCChatData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:indexPath.row - 1];
110     return MAX(data.insets.top + data.view.frame.size.height + data.insets.bottom, 52);
111 }
112 
113 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
114 {
115     //Header based on snapInterval
116     if (indexPath.row == 0) {
117         static NSString *cellId = @"HeaderCell";
118         YXYCChatHeaderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
119         YXYCChatData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:0];
120         if (cell == nil) {
121             cell = [[YXYCChatHeaderTableViewCell alloc] init];
122         }
123         cell.date = data.date;
124         return cell;
125     }
126     //Standard
127     static NSString * cellId = @"ChatCell";
128     YXYCChatTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
129     YXYCChatData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:indexPath.row - 1];
130     if (cell == nil) {
131         cell = [[YXYCChatTableViewCell alloc] init];
132     }
133     cell.data = data;
134     return cell;
135 }
136 
137 @end
原文地址:https://www.cnblogs.com/lantu1989/p/4745648.html