YDConversationViewController
YDConversationViewController的目的是现实用户和其好友之间的会话信息。用户发送的消息和接收到得消息分别位于UITableView的两侧。
添加行高和最多显示的聊天行数定义到YDDefinitions.h
//YDConversationViewController
#define lineHeight 16.0f
#define maxChatLines 4
创建继承于UIViewController的YDConversationViewController,YDConversationViewController.h
#import <UIKit/UIKit.h>
@interface YDConversationViewController : UIViewController
- (void)showConversationForJIDString:(NSString *)jidString;
@end
YDConversationViewController.m,首先import需要的头文件,然后声明本类遵从UITableViewDataSource,UITableViewDelegate和UITextViewDelegate歇息。最后创建程序需要的一些成员变量。
#import "YDConversationViewController.h"
#import "DDLog.h"
#import "DDTTYLogger.h"
#import <CoreData/CoreData.h>
#import "YDAppDelegate.h"
#if DEBUG
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#else
static const int ddLogLevel = LOG_LEVEL_INFO;
#endif
@interface YDConversationViewController ()<UITableViewDataSource,UITableViewDelegate,UITextViewDelegate>
{
float prevLines;
UIButton *sendButton;
}
@property (nonatomic,strong) NSString *cleanName;
@property (nonatomic,strong) NSString *conversationJidString;
@property (nonatomic,strong) UITableView *mtableView;
@property (nonatomic,strong) NSMutableArray* chats;
@property (nonatomic,strong) UILabel *statusLabel;
@property (nonatomic,strong) UIView *sendView;
@property (nonatomic,strong) UITextView *msgText;
@end
监听kNewMessage和kChatStatus消息。
#pragma mark view appearance
-(void)viewWillAppear:(BOOL)animated
{
//Add Observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(newMessageReceived:) name:kNewMessage object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusUpdateReceived:) name:kChatStatus object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
//Remove notifications
[[NSNotificationCenter defaultCenter] removeObserver:self name:kChatStatus object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kNewMessage object:nil];
}
loadData方法,在viewDidLoad和收到新消息时调用:
-(void)loadData
{
if (self.chats)
self.chats =nil;
self.chats = [[NSMutableArray alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Chat"
inManagedObjectContext:[self appDelegate].managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"jidString == %@",self.conversationJidString];
[fetchRequest setPredicate:predicate];
NSError *error=nil;
NSArray *fetchedObjects = [[self appDelegate].managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *obj in fetchedObjects)
{
[self.chats addObject:obj];
//Since they are now visible set the isNew to NO
Chat *thisChat = (Chat *)obj;
if ([thisChat.isNew boolValue])
thisChat.isNew = [NSNumber numberWithBool:NO];
}
//Save changes
error = nil;
if (![[self appDelegate].managedObjectContext save:&error])
{
NSLog(@"error saving");
}
//reload the table view
[self.mtableView reloadData];
[self scrollToBottomAnimated:YES];
}
sendMessage方法,当用户完成输入后,点击发送按钮时执行,将数据发送出去。
#pragma mark send message
-(IBAction)sendMessage:(id)sender
{
NSString *messageStr = self.msgText.text;
if([messageStr length] > 0)
{
//send chat message
NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
[body setStringValue:messageStr];
NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
[message addAttributeWithName:@"type" stringValue:@"chat"];
[message addAttributeWithName:@"to" stringValue:self.conversationJidString];
[message addChild:body];
NSXMLElement *status = [NSXMLElement elementWithName:@"active" xmlns:@"http://jabber.org/protocol/chatstates"];
[message addChild:status];
[[self appDelegate].xmppStream sendElement:message];
// We need to put our own message also in CoreData of course and reload the data
Chat *chat = [NSEntityDescription
insertNewObjectForEntityForName:@"Chat"
inManagedObjectContext:[self appDelegate].managedObjectContext];
chat.messageBody = messageStr;
chat.messageDate = [NSDate date];
chat.hasMedia=[NSNumber numberWithBool:NO];
chat.isNew=[NSNumber numberWithBool:NO];
chat.messageStatus=@"send";
chat.direction = @"OUT";
chat.groupNumber=@"";
chat.isGroupMessage=[NSNumber numberWithBool:NO];
chat.jidString = self.conversationJidString;
NSError *error = nil;
if (![[self appDelegate].managedObjectContext save:&error])
{
NSLog(@"error saving");
}
}
self.msgText.text=@"";
if ([self.msgText isFirstResponder])
[self.msgText resignFirstResponder ];
//Reload our data
[self loadData];
//Restore the Screen
[self showFullTableView];
}
用户输入时,发送composing消息:
#pragma mark UITextView Delegate
-(void)textViewDidChange:(UITextView *)textView
{
UIFont* systemFont = [UIFont boldSystemFontOfSize:12];
int width = 185.0, height = 10000.0;
NSMutableDictionary *atts = [[NSMutableDictionary alloc] init];
[atts setObject:systemFont forKey:NSFontAttributeName];
CGRect textSize = [self.msgText.text boundingRectWithSize:CGSizeMake(width, height)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:atts
context:nil];
float textHeight = textSize.size.height;
float lines = textHeight / lineHeight;
// NSLog(@"textViewDidChange h: %0.f lines %0.f ",textHeight,lines);
if (lines >=4)
lines=4;
if (lines < 1.0)
lines = 1.0;
//Send your chat state
NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
[message addAttributeWithName:@"type" stringValue:@"chat"];
[message addAttributeWithName:@"to" stringValue:self.conversationJidString];
NSXMLElement *status = [NSXMLElement elementWithName:@"composing" xmlns:@"http://jabber.org/protocol/chatstates"];
[message addChild:status];
[[self appDelegate].xmppStream sendElement:message];
if (prevLines!=lines)
[self shortenTableView];
prevLines=lines;
}
-(void)textViewDidBeginEditing:(UITextView *)textView
{ [UIView beginAnimations:@"moveView" context:nil];
[UIView setAnimationDuration:0.3];
self.sendView.frame = CGRectMake(0,ScreenHeight-270,ScreenWidth,56);
[UIView commitAnimations];
[self shortenTableView];
[self.msgText becomeFirstResponder];
//Send your chat state
NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
[message addAttributeWithName:@"type" stringValue:@"chat"];
[message addAttributeWithName:@"to" stringValue:self.conversationJidString];
NSXMLElement *status = [NSXMLElement elementWithName:@"composing" xmlns:@"http://jabber.org/protocol/chatstates"];
[message addChild:status];
[[self appDelegate].xmppStream sendElement:message];
}
cell方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
Chat* chat = [self.chats objectAtIndex:indexPath.row];
UIFont* systemFont = [UIFont boldSystemFontOfSize:12];
int width = 185.0, height = 10000.0;
NSMutableDictionary *atts = [[NSMutableDictionary alloc] init];
[atts setObject:systemFont forKey:NSFontAttributeName];
CGRect textSize = [self.msgText.text boundingRectWithSize:CGSizeMake(width, height)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:atts
context:nil];
float textHeight = textSize.size.height;
//Body
UITextView *body = [[UITextView alloc] initWithFrame:CGRectMake(70,3,240,textHeight+10)];
body.backgroundColor = [UIColor clearColor];
body.editable = NO;
body.scrollEnabled = NO;
body.backgroundColor=[UIColor clearColor];
body.textColor=[UIColor blackColor];
body.textAlignment=NSTextAlignmentLeft;
[body setFont:[UIFont boldSystemFontOfSize:12]];
body.text = chat.messageBody;
[body sizeToFit];
//SenderLabel
UILabel *senderLabel = [[UILabel alloc] initWithFrame:CGRectMake(10,textHeight +10 ,300,20)];
senderLabel.backgroundColor=[UIColor clearColor];
senderLabel.font = [UIFont systemFontOfSize:12];
senderLabel.textColor=[UIColor blackColor];
senderLabel.textAlignment=NSTextAlignmentLeft;
UIImage *bgImage;
float senderStartX;
if ([chat.direction isEqualToString:@"IN"])
{ // left aligned
bgImage = [[UIImage imageNamed:@"leftballoon.png"] stretchableImageWithLeftCapWidth:0 topCapHeight:15];
body.frame=CGRectMake(10,3,240.0,textHeight+10 );
senderLabel.frame=CGRectMake(19,textHeight+15,250,13);
senderLabel.text= [NSString stringWithFormat:@"%@: %@",self.cleanName,[YDHelper dayLabelForMessage:chat.messageDate]];
senderStartX=19;
}
else
{
//right aligned
bgImage = [[UIImage imageNamed:@"rightballoonred.png"] stretchableImageWithLeftCapWidth:0 topCapHeight:15];
body.frame=CGRectMake(45,3,240.0,textHeight+10);
senderLabel.frame=CGRectMake(55,textHeight+15,250,13);
senderLabel.text= [NSString stringWithFormat:@"You %@" ,[YDHelper dayLabelForMessage:chat.messageDate]];
senderStartX=55;
}
CGFloat heightForThisCell = textHeight + 40;
UIImageView *balloonHolder = [[UIImageView alloc] initWithFrame:CGRectMake(0,5,320,textHeight+35 )];
balloonHolder.image = bgImage;
balloonHolder.backgroundColor=[UIColor clearColor];
//Create the content holder
UIView *cellContentView = [[UIView alloc] initWithFrame:CGRectMake(0,5,320,heightForThisCell)];
[cellContentView addSubview:balloonHolder];
[cellContentView addSubview:body];
[cellContentView addSubview:senderLabel];
cell.backgroundView = cellContentView;
return cell;
}