星空网 > 软件开发 > 操作系统

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

这篇博客的代码是直接在上篇博客的基础上增加的,先给出部分代码,最后会给出能实现简单功能的完整代码。

UI进阶 即时通讯之XMPP登录、注册

 

1、好友列表

初始化好友花名册

#pragma mark - 管理好友    // 获取管理好友的单例对象    XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];    // 用管理好友的单例对象初始化Roster花名册    // 好友操作是耗时操作    self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];    // 在通道中激活xmppRoster    [self.xmppRoster activate:self.xmppStream];    // 设置代理    [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];

XMPPRoster代理方法

  好友列表

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天images/loading.gif' data-original="data:image/png;base64,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

添加好友

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天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

 

  XMPPManager.h 新增代码

 

#pragma mark - 添加好友- (void)addFriend;#pragma mark - 删除好友- (void)removeFriendWithName:(NSString *)userName;#pragma mark - 手动断开连接(注销)- (void)disconnectionToServer;

 

XMPPManager.m 新增代码

/// 接收要添加好友的名字@property (nonatomic, strong) UITextField *addText;#pragma mark - 重写初始化方法- (instancetype)init {  if (self = [super init]) {#pragma mark - 创建通道    // 初始化通道对象    self.xmppStream = [[XMPPStream alloc] init];    // 设置Openfire服务器主机名    self.xmppStream.hostName = kHostName;    // 设置服务器端口号    self.xmppStream.hostPort = kHostPort;    // 设置代理    [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];    #warning -----------------以下是该方法中新增加的代码-----------------------#pragma mark - 管理好友    // 获取管理好友的单例对象    XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];    // 用管理好友的单例对象初始化Roster花名册    // 好友操作是耗时操作    self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];    // 在通道中激活xmppRoster    [self.xmppRoster activate:self.xmppStream];    // 设置代理    [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];    #warning -----------------以上是该方法中新增加的代码-----------------------  }  return self;}#pragma mark -----------------以下是管理好友列表----------------#pragma mark - 添加好友- (void)addFriend {  NSLog(@"manager - 添加好友 %d", __LINE__);  UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"添加好友" message:@"请输入要添加好友的名字" preferredStyle:UIAlertControllerStyleAlert];  __weak typeof(self)weakSelf = self;  [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {    // 接收输入的好友名字    weakSelf.addText = textField;  }];  UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];  UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {    NSLog(@"======%@", weakSelf.addText.text);    // 使用JID记录    XMPPJID *addJID = [XMPPJID jidWithUser:weakSelf.addText.text domain:kDomin resource:kResource];    // 监听好友的动作    [weakSelf.xmppRoster subscribePresenceToUser:addJID];    // 添加好友    [weakSelf.xmppRoster addUser:addJID withNickname:weakSelf.addText.text];  }];  [alertController addAction:sureAction];  [alertController addAction:cancleAction];  [[self getCurrentVC ]presentViewController:alertController animated:YES completion:nil];}#pragma mark - 删除好友- (void)removeFriendWithName:(NSString *)userName {  NSLog(@"manager删除好友 %d", __LINE__);  // 使用JID记录要删除的用户名  XMPPJID *removeJID = [XMPPJID jidWithUser:userName domain:kDomin resource:kResource];  // 停止监听好友  [self.xmppRoster unsubscribePresenceFromUser:removeJID];  // 删除好友  [self.xmppRoster removeUser:removeJID];}#pragma mark - 获取当前屏幕显示的viewcontroller- (UIViewController *)getCurrentVC{  UIViewController *result = nil;    UIWindow * window = [[UIApplication sharedApplication] keyWindow];  if (window.windowLevel != UIWindowLevelNormal)  {    NSArray *windows = [[UIApplication sharedApplication] windows];    for(UIWindow * tmpWin in windows)    {      if (tmpWin.windowLevel == UIWindowLevelNormal)      {        window = tmpWin;        break;      }    }  }    UIView *frontView = [[window subviews] objectAtIndex:0];  id nextResponder = [frontView nextResponder];    if ([nextResponder isKindOfClass:[UIViewController class]])    result = nextResponder;  else    result = window.rootViewController;    return result;}

RosterListTableViewController.m 好友列表显示页面

#import "RosterListTableViewController.h"#import "XMPPManager.h"#import "ChatTableViewController.h"@interface RosterListTableViewController ()<XMPPRosterDelegate, XMPPStreamDelegate>/// 好友列表@property (nonatomic, strong) NSMutableArray *allRosterArray;/// 用来存储发送好友请求者的JID@property (nonatomic, strong) XMPPJID *fromJID;@end@implementation RosterListTableViewController- (void)viewDidLoad {  [super viewDidLoad];  // 初始化数组  self.allRosterArray = [NSMutableArray array];    [[XMPPManager sharedXMPPManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];  [[XMPPManager sharedXMPPManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];  self.title = @"好友列表";    // 添加按钮  self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addFriendAction)];  // 返回按钮  self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"注销" style:UIBarButtonItemStylePlain target:self action:@selector(cancleAction)];    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"RosterCell"];}#pragma mark - 添加好友按钮点击事件- (void)addFriendAction {    [[XMPPManager sharedXMPPManager] addFriend];}#pragma mark - 注销按钮点击事件- (void)cancleAction {  // 注销  [[XMPPManager sharedXMPPManager] disconnectionToServer];  [self.navigationController popViewControllerAnimated:YES];}#pragma mark - Table view data source- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {  return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  return self.allRosterArray.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RosterCell" forIndexPath:indexPath];    // 根据项目情况分析,合理添加判断  if (self.allRosterArray.count > 0) {    // 获取用户    XMPPJID *jid = [self.allRosterArray objectAtIndex:indexPath.row];    cell.textLabel.text = jid.user;    NSLog(@"bare %@", jid.bare);  }    return cell;}- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {  return YES;}- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {  if (editingStyle == UITableViewCellEditingStyleDelete) {    // 删除一个好友    XMPPJID *jid = self.allRosterArray[indexPath.row];    // 根据名字删除好友    [[XMPPManager sharedXMPPManager] removeFriendWithName:jid.user];    // 从数组中移除    [self.allRosterArray removeObjectAtIndex:indexPath.row];    [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];  } else if (editingStyle == UITableViewCellEditingStyleInsert) {    }  }#pragma mark - 点击cell进入聊天界面- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  ChatTableViewController *chatTVC = [[ChatTableViewController alloc] initWithStyle:UITableViewStylePlain];  // 将当前好友的JID传到聊天界面  chatTVC.chatWithJID = self.allRosterArray[indexPath.row];  [self.navigationController pushViewController:chatTVC animated:YES];}#pragma mark - ----------------XMPPRosterDelegate代理方法----------------#pragma mark - 开始获取好友- (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender {  NSLog(@"listTVC 开始获取好友 %d", __LINE__);}#pragma mark - 结束获取好友- (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender {  NSLog(@"listTVC 获取好友结束 %d", __LINE__);  // 当前页面是用于显示好友列表的,所以在结束获取好友的代理方法中要进行页面刷新页面,然后将数据显示。  // 刷新UI  [self.tableView reloadData];}#pragma mark - 接收好友信息// 获取好友列表时会执行多次,每次获取一个好友信息并将该好友信息添加到数组中// 发送完添加好友请求会执行// 同意别人的好友请求会执行// 删除好友时会执行- (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DD)item {  NSLog(@"listTVC 接收好友信息 %d", __LINE__);  /**   * 好友信息状态有5种    both - 互为好友    none - 互不为好友    to - 请求添加对方为好友,对方还没有同意    from - 对方添加我为好友,自己还没有同意    remove - 曾经删除的好友   */    // 自己和对方之间的关系  NSString *description = [[item attributeForName:@"subscription"] stringValue];  NSLog(@"关系%@", description);  // 显示我的好友  if ([description isEqualToString:@"both"]) {    // 添加好友    // 获取好友的JID    NSString *friendJID = [[item attributeForName:@"jid"] stringValue];    XMPPJID *jid = [XMPPJID jidWithString:friendJID];    // 如果数组中含有这个用户,那么不添加进数组    if ([self.allRosterArray containsObject:jid]) {      NSLog(@"已经有该好友");      return;    }    // 添加好友到数组中    [self.allRosterArray addObject:jid];    // 在TableView的最后一个cell下面添加这条数据    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.allRosterArray.count - 1 inSection:0];    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];  }}#pragma mark - 接收到添加好友的请求,选择接受or拒绝- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence {  NSLog(@"listTVC 接收添加好友的请求 %d", __LINE__);  self.fromJID = presence.from;  // 需要相关的提醒框去确定是否接受好友请求  UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"请求添加好友" message:@"是否同意" preferredStyle:UIAlertControllerStyleAlert];  __weak typeof(self)weakSelf = self;  UIAlertAction *acceptAction = [UIAlertAction actionWithTitle:@"同意" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {    // 添加到花名册    [[XMPPManager sharedXMPPManager].xmppRoster acceptPresenceSubscriptionRequestFrom:weakSelf.fromJID andAddToRoster:YES];  }];  UIAlertAction *rejectAction = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {    [[XMPPManager sharedXMPPManager].xmppRoster rejectPresenceSubscriptionRequestFrom:weakSelf.fromJID];  }];  [alertController addAction:acceptAction];  [alertController addAction:rejectAction];  [self presentViewController:alertController animated:YES completion:nil];}#pragma mark - ----------------XMPPStreamDelegate代理方法----------------#pragma mark - 判断好友是否处于上线状态- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {  NSLog(@"listTVC 判断好友是否处于上线状态 %@ %d", presence.status, __LINE__);  NSString *type = presence.type;  NSString *presenceUser = presence.to.user;  // 判断当前用户是否为好友  if ([presenceUser isEqualToString:[sender myJID].user]) {    if ([type isEqualToString:@"available"]) {      NSLog(@"该用户处于上线状态");    } else if ([type isEqualToString:@"unavailable"]) {      NSLog(@"该用户处于下线状态");    }  }}@end

2、聊天

聊天的规则:

1、从服务器获取聊天记录

2、根据消息类XMPPMessageArchiving_Message_CoreDataObject的对象的属性isOutgoing来判断该消息是不是对方发送过来的消息 YES - 对方发送的消息, NO - 自己发送给对方的消息

3、发送消息

4、接收消息

  初始化消息归档

#pragma mark - 初始化消息归档    // 获取管理消息的存储对象    XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];    // 进行消息管理器的初始化    self.xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()];    // 在通道中激活xmppMessageArchiving    [self.xmppMessageArchiving activate:self.xmppStream];    // 设置代理    [self.xmppMessageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];    // 设置管理上下文 (此时不再从AppDelegate获取)    self.context = storage.mainThreadManagedObjectContext;

获取聊天记录(使用CoreData的方式)

1、创建请求

2、创建实体描述,实体名:   XMPPMessageArchiving_Message_CoreDataObject

3、创建谓词查询条件,条件:streamBareJidStr == 本人Jid AND bareJidStr == 好友Jid

4、创建排序对象,排序条件:timestamp

5、执行请求

接受、发送消息用到的代理方法

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

 

消息气泡

 

 

 

 UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

1 /// 和聊天相关的属性,消息归档2 @property (nonatomic, strong) XMPPMessageArchiving *xmppMessageArchiving;3 /// 管理数据库上下文4 @property (nonatomic, strong) NSManagedObjectContext *context;

XMPPManager.m 新增代码

#pragma mark - 重写初始化方法- (instancetype)init {  if (self = [super init]) {#pragma mark - 创建通道    // 初始化通道对象    self.xmppStream = [[XMPPStream alloc] init];    // 设置Openfire服务器主机名    self.xmppStream.hostName = kHostName;    // 设置服务器端口号    self.xmppStream.hostPort = kHostPort;    // 设置代理    [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];        #pragma mark - 管理好友    // 获取管理好友的单例对象    XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];    // 用管理好友的单例对象初始化Roster花名册    // 好友操作是耗时操作    self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];    // 在通道中激活xmppRoster    [self.xmppRoster activate:self.xmppStream];    // 设置代理    [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];    #warning -----------------以下是该方法中新增加的代码-----------------------#pragma mark - 初始化管理归档    // 获取管理消息的存储对象    XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];    // 进行消息管理器的初始化    self.xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()];    // 在通道中激活xmppMessageArchiving    [self.xmppMessageArchiving activate:self.xmppStream];    // 设置代理    [self.xmppMessageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];    // 设置管理上下文 (此时不再从AppDelegate获取)    self.context = storage.mainThreadManagedObjectContext;#warning -----------------以上是该方法中新增加的代码-----------------------  }  return self;}

从好友列表页面点击cell进入聊天界面

  RosterListTableViewController.m 好友列表界面新增代码

 

#pragma mark - 点击cell进入聊天界面- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  ChatTableViewController *chatTVC = [[ChatTableViewController alloc] initWithStyle:UITableViewStylePlain];  // 将当前好友的JID传到聊天界面  chatTVC.chatWithJID = self.allRosterArray[indexPath.row];  [self.navigationController pushViewController:chatTVC animated:YES];}

 

 聊天界面

  ChatTableViewController.h

 

#import <UIKit/UIKit.h>#import "XMPPManager.h"@interface ChatTableViewController : UITableViewController/// 当前和谁在聊天@property (nonatomic, strong) XMPPJID *chatWithJID;@end

ChatTableViewController.m

#import "ChatTableViewController.h"#import "ChatTableViewCell.h"@interface ChatTableViewController ()<XMPPStreamDelegate>@property (nonatomic, strong) NSMutableArray *allMessageArray;@end@implementation ChatTableViewController- (void)viewDidLoad {  [super viewDidLoad];  self.allMessageArray = [NSMutableArray array];  // 隐藏分割线  self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;  // 注册cell  [self.tableView registerClass:[ChatTableViewCell class] forCellReuseIdentifier:@"chatCell"];  // 发送按钮  self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelAction)];  // 取消按钮 20   self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"发送" style:UIBarButtonItemStylePlain target:self action:@selector(sendMessageAction)];  [[XMPPManager sharedXMPPManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];  // 获取显示消息的方法  [self showMessage];  }#pragma mark - 取消按钮点击事件- (void)cancelAction {  // 返回上一界面  [self.navigationController popViewControllerAnimated:YES];}#pragma mark - 发送消息按钮点击事件- (void)sendMessageAction {  XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatWithJID];  // 设置message的body为固定值 (没有实现发送自定义消息)  [message addBody:@"我爱你"];  // 通过通道进行消息发送  [[XMPPManager sharedXMPPManager].xmppStream sendElement:message];}#pragma mark - 显示消息- (void)showMessage {  // 获取管理对象上下文  NSManagedObjectContext *context = [XMPPManager sharedXMPPManager].context;  // 初始化请求对象  NSFetchRequest *request = [[NSFetchRequest alloc] init];  // 获取实体  NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context];  // 设置查询请求的实体  [request setEntity:entity];  // 设置谓词查询 (当前用户的jid,对方用户的jid) (根据项目需求而定)  request.predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@",[XMPPManager sharedXMPPManager].xmppStream.myJID.bare,self.chatWithJID.bare];  // 按照时间顺序排列  NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];  [request setSortDescriptors:@[sort]];  // 获取到存储在数据库中的聊天记录  NSArray *resultArray = [context executeFetchRequest:request error:nil];  // 先清空消息数组 (根据项目需求而定)  [self.allMessageArray removeAllObjects];  // 将结果数组赋值给消息数组  self.allMessageArray = [resultArray mutableCopy];  // 刷新UI  [self.tableView reloadData];  // 当前聊天记录跳到最后一行  if (self.allMessageArray.count > 0) {    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.allMessageArray.count - 1 inSection:0];    // 跳到最后一行    [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];  }  [context save:nil];}#pragma mark - Table view data source- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {  return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  return self.allMessageArray.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  ChatTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"chatCell" forIndexPath:indexPath];  // 数组里存储的是XMPPMessageArchiving_Message_CoreDataObject对象  XMPPMessageArchiving_Message_CoreDataObject *message = [self.allMessageArray objectAtIndex:indexPath.row];  // 设置cell中的相关数据  // 根据isOutgoing判断是不是对方发送过来的消息 YES - 对方发送的消息, NO - 自己发送给对方的消息  cell.isOut = message.isOutgoing;  cell.message = message.body;    return cell;}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {  // cell的高度并没有自适应  return 70;}#pragma mark - ------------XMPPStreamDelegate相关代理------------#pragma mark - 已经发送消息- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message {  // 重新对消息进行操作  [self showMessage];}#pragma mark - 已经接收消息- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {  // 重新对消息进行操作  [self showMessage];}#pragma mark - 消息发送失败- (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error {  NSLog(@"消息发送失败");}@end

自定义cell

  ChatTableViewCell.h

 

#import <UIKit/UIKit.h>@interface ChatTableViewCell : UITableViewCell/// 判断是不是对方发送过来的消息 YES - 对方发送的消息, NO - 自己发送给对方的消息@property (nonatomic, assign) BOOL isOut;/// 消息内容@property (nonatomic, copy) NSString *message;@end

 

ChatTableViewCell.m

 

#import "ChatTableViewCell.h"@interface ChatTableViewCell ()/// 头像@property(nonatomic,strong)UIImageView * headerImageView;/// 消息框背景@property(nonatomic,strong)UIImageView * backgroundImageView;/// 显示每一条聊天内容@property(nonatomic,strong)UILabel * contentLabel;@end@implementation ChatTableViewCell//使用懒加载创建并初始化所有UI控件- (UILabel *)contentLabel{  if (_contentLabel == nil) {    _contentLabel = [[UILabel alloc] init];  }  return _contentLabel;}- (UIImageView *)backgroundImageView{  if (_backgroundImageView == nil) {    _backgroundImageView = [[UIImageView alloc] init];  }  return _backgroundImageView;}- (UIImageView *)headerImageView{  if (_headerImageView == nil) {    _headerImageView = [[UIImageView alloc] init];  }  return _headerImageView;}- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];  if (self) {    //设置cell不能选中    self.selectionStyle = UITableViewCellSelectionStyleNone;        [self.contentView addSubview:self.backgroundImageView];    [self.contentView addSubview:self.headerImageView];    [self.backgroundImageView addSubview:self.contentLabel];      }  return self;}- (void)awakeFromNib {  // Initialization code    }//重写isOut的setter方法,来设定cell上的不同布局- (void)setIsOut:(BOOL)isOut{  _isOut = isOut;  CGRect rect = self.frame;  if (_isOut) {    self.headerImageView.frame = CGRectMake(rect.size.width-50, 10, 50, 50);    self.headerImageView.image = [UIImage imageNamed:@"nike"];  }else{    self.headerImageView.frame = CGRectMake(0, 10, 50, 50);    self.headerImageView.image = [UIImage imageNamed:@"keji"];  }}//重写message方法,在cell上显示聊天记录- (void)setMessage:(NSString *)message{  if (_message != message) {    _message = message;    self.contentLabel.text = _message;    //    self.contentLabel.numberOfLines = 0;    [self.contentLabel sizeToFit];        CGRect rect = self.frame;    if (self.isOut) {//发出去的      // 消息气泡      self.backgroundImageView.image = [[UIImage imageNamed:@"chat_to"] stretchableImageWithLeftCapWidth:45 topCapHeight:40];      self.backgroundImageView.frame = CGRectMake(rect.size.width - self.contentLabel.frame.size.width - 50-20, 10, self.contentLabel.frame.size.width+20, rect.size.height-20);    }else{//接收的      self.backgroundImageView.image = [[UIImage imageNamed:@"chat_from"] stretchableImageWithLeftCapWidth:45 topCapHeight:40];      self.backgroundImageView.frame = CGRectMake(50, 10,self.contentLabel.frame.size.width+40, rect.size.height-20);    }    //因为contentLabel已经自适应文字大小,故不用设置宽高,但需要设置位置    self.contentLabel.center = CGPointMake(self.backgroundImageView.frame.size.width/2.0, self.backgroundImageView.frame.size.height/2.0);      }}@end

 

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

1、将图片/语音上传到服务器

2、根据和服务器的约定,拼好文件在服务器的地址(即图片/语音的URL)

3、调用XMPP发送消息方法,将地址发送出去

4、在接收端接收到的为一条文本信息,里面仅仅是一个指向资源文件的URL地址

5、在拿到URL后进行需要的操作(即请求图片/语音显示到页面上)

 

 

 

 

 






原标题:UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

关键词:

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

深圳马来西亚运输:https://www.goluckyvip.com/tag/90918.html
东莞寄马来西亚:https://www.goluckyvip.com/tag/90919.html
武汉到马来西亚快递:https://www.goluckyvip.com/tag/90920.html
福建寄马来西亚:https://www.goluckyvip.com/tag/90921.html
昆明马来西亚物流:https://www.goluckyvip.com/tag/90922.html
深圳寄快递到马来西亚:https://www.goluckyvip.com/tag/90923.html
在英国有分公司的中国公司:https://www.xlkjsw.com/tag/30029.html
英国成立:https://www.xlkjsw.com/tag/30031.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流