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:@"\n"]) { 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
时间: 2024-09-29 19:45:57