EaseUI 使用指南


EaseUI已不再维护,新用户建议集成新版UI库 'EaseIMKit' 文档地址:EaseIMKit集成

EaseUI 封装了 IM 功能常用的控件(如聊天会话、会话列表、联系人列表)。旨在帮助开发者快速集成环信 SDK。

源码地址:

以下是EaseUI集成参考视频,您可以通过视频学习如何集成环信SDK。

方法一:

pod 'EaseUI', :git => 'https://github.com/easemob/easeui-ios-hyphenate-cocoapods.git'
pod 'EaseUILite', :git =>'https://github.com/easemob/easeui-ios-hyphenate-cocoapods.git'

如果要指定版本,可以在后面添加tag,如

pod 'EaseUI', :git => 'https://github.com/easemob/easeui-ios-hyphenate-cocoapods.git', :tag => ‘3.3.4’

具体tag号和对应sdk版本号,可以从 https://github.com/easemob/easeui-ios-hyphenate-cocoapods/tags查看

注意:

EaseUI:对应Hyphenate SDK(sdk包含实时音视频)

EaseUILite:对应HyphenateLite SDK(sdk不包含实时音视频)

Pod集成EaseUI时,会同时通过Pod集成SDK

方法二:

  • 集成 EaseUI 前,首先需要集成环信 iOS SDK,参考:集成文档
  • 参考ChatDemo3.0 导入的方式,直接将EaseUI拖入已经集成SDK的项目中

注意:

  • 添加的SDK要和EaseUI是同时下载的(目的是版本一致)。
  • 如果使用Lite版本SDK,并用拖动的方式添加EaseUI, 需要在 Build Settings > GCC_PREPROCESSOR_DEFINITIONS 中添加 ENABLE_LITE=1 (等号左右不能有空格)

easeui中包含了拍照,发语音,发图片,发位置的功能,使用了录音,摄像头,相册,地理位置的权限。需要在您项目的info.plist中添加对应权限。

第 1 步:引入相关头文件 #import “EaseUI.h”。

第 2 步:在工程的 AppDelegate 中的以下方法中,调用 EaseUI 对应方法。(注: 此方法不需要重复调用)

[[EaseSDKHelper shareHelper] hyphenateApplication:application
                    didFinishLaunchingWithOptions:launchOptions
                                               appkey:appkey
                                     apnsCertName:apnsCertName
                                      otherConfig:@{kSDKConfigEnableConsoleLogger:[NSNumber numberWithBool:YES]}];

创建聊天会话、传递用户或群 ID 和会话类型(EMConversationType)。

EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:@"8001" conversationType:EMConversationTypeChat];

EaseRefreshTableViewController提供了列表上拉加载、下拉刷新(加载)功能的UIViewController,其中已添加控件UITableView,默认未开启上拉加载、下来刷新(加载)的功能

实现上拉加载功能

继承自EaseRefreshTableViewController的子类,开启上拉加载需要设置showRefreshFooter为YES,并重写父类方法- (void)tableViewDidTriggerFooterRefresh;,如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshFooter = YES;
}

- (void)tableViewDidTriggerFooterRefresh {
   //子类需要重写此方法
   
}

实现下拉加载(刷新)功能

继承自EaseRefreshTableViewController的子类,开启下拉加载(刷新)需要设置showRefreshHeader为YES,并重写父类方法- (void)tableViewDidTriggerHeaderRefresh;,如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshHeader = YES;
}

- (void)tableViewDidTriggerHeaderRefresh {
   //子类需要重写此方法
   
}

EaseUI 提供现成的聊天会话 ViewController,可以通过继承 EaseMessageViewController 方式(参考 ChatDemo-UI3.0 中 ChatViewController)实现对聊天会话的扩展。

也可以直接使用 EaseMessageViewController,通过 EaseMessageViewControllerDelegate 和 EaseMessageViewControllerDataSource 两个协议实现对 EaseMessageViewController 的扩展。

实现自定义聊天样式

EaseMessageViewControllerDelegate

获取自定义消息 cell,根据 messageModel,用户自己判断是否显示自定义消息 cell。如果返回 nil 会显示默认;如果返回 cell 会显示用户自定义消息cell。

/*!
 @method
 @brief 获取消息自定义cell
 @discussion 用户根据messageModel判断是否显示自定义cell。返回nil显示默认cell,否则显示用户自定义cell
 @param tableView 当前消息视图的tableView
 @param messageModel 消息模型
 @result 返回用户自定义cell
 */
- (UITableViewCell *)messageViewController:(UITableView *)tableView
                       cellForMessageModel:(id<IMessageModel>)messageModel;

/*!
 @method
 @brief 获取消息cell高度
 @discussion 用户根据messageModel判断,是否自定义显示cell的高度
 @param viewController 当前消息视图
 @param messageModel 消息模型
 @param cellWidth 视图宽度
 @result 返回用户自定义cell
 */
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
           heightForMessageModel:(id<IMessageModel>)messageModel
                   withCellWidth:(CGFloat)cellWidth;
                   
//具体创建自定义Cell的样例:
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model
{
    //样例为如果消息是文本消息显示用户自定义cell
    if (model.bodyType == eMessageBodyType_Text) {
        NSString *CellIdentifier = [CustomMessageCell cellIdentifierWithModel:model];
        //CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
        CustomMessageCell *cell = (CustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[CustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        }
        cell.model = model;
        return cell;
    }
    return nil;
}

- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
           heightForMessageModel:(id<IMessageModel>)messageModel
                   withCellWidth:(CGFloat)cellWidth
{
    //样例为如果消息是文本消息使用用户自定义cell的高度
    if (messageModel.bodyType == EMMessageBodyTypeText) {
        //CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
        return [CustomMessageCell cellHeightWithModel:messageModel];
    }
    return 0.f;
}

通过自定义cell展示动态表情的效果图:

通过自定义cell展示动态表情的效果图

选中消息的回调

/*!
 @method
 @brief 选中消息的回调
 @discussion 用户根据messageModel判断,是否自定义处理消息选中时间。返回YES为自定义处理,返回NO为默认处理
 @param viewController 当前消息视图
 @param messageModel 消息模型
 @result 是否采用自定义处理
 */
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
        didSelectMessageModel:(id<IMessageModel>)messageModel;
        
//选中消息回调的样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
        didSelectMessageModel:(id<IMessageModel>)messageModel
{
    BOOL flag = NO;
    //样例为如果消息是文件消息用户自定义处理选中逻辑
    switch (messageModel.bodyType) {
        case EMMessageBodyTypeImage:
        case EMMessageBodyTypeLocation:
        case EMMessageBodyTypeVideo:
        case EMMessageBodyTypeVoice:
            break;
        case EMMessageBodyTypeFile:
        {
            flag = YES;
            NSLog(@"用户自定义实现");
        }
            break;
        default:
            break;
    }
    return flag;
}

用户选中头像的回调

/*!
 @method
 @brief 点击消息头像
 @discussion 获取用户点击头像回调
 @param viewController 当前消息视图
 @param messageModel 消息模型
 @result
 */
- (void)messageViewController:(EaseMessageViewController *)viewController
    didSelectAvatarMessageModel:(id<IMessageModel>)messageModel;
    
//获取用户点击头像回调的样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
   didSelectAvatarMessageModel:(id<IMessageModel>)messageModel
{
    //UserProfileViewController用户自定义的个人信息视图
    //样例的逻辑是选中消息头像后,进入该消息发送者的个人信息
    UserProfileViewController *userprofile = [[UserProfileViewController alloc] initWithUsername:messageModel.message.from];
    [self.navigationController pushViewController:userprofile animated:YES];
}

录音按钮状态的回调

/*!
 @method
 @brief 底部录音功能按钮状态回调
 @discussion 获取底部录音功能按钮状态回调,根据EaseRecordViewType,用户自定义处理UI的逻辑
 @param viewController 当前消息视图
 @param recordView 录音视图
 @param type 录音按钮当前状态
 @result
 */
- (void)messageViewController:(EaseMessageViewController *)viewController
              didSelectRecordView:(UIView *)recordView
                withEvenType:(EaseRecordViewType)type;
                
//录音按钮状态的回调样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
          didSelectRecordView:(UIView *)recordView
                 withEvenType:(EaseRecordViewType)type
{
    /*
        EaseRecordViewTypeTouchDown,//录音按钮按下
        EaseRecordViewTypeTouchUpInside,//手指在录音按钮内部时离开
        EaseRecordViewTypeTouchUpOutside,//手指在录音按钮外部时离开
        EaseRecordViewTypeDragInside,//手指移动到录音按钮内部
        EaseRecordViewTypeDragOutside,//手指移动到录音按钮外部
    */
    //根据type类型,用户自定义处理UI的逻辑
    switch (type) {
        case EaseRecordViewTypeTouchDown:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView  recordButtonTouchDown];
            }
        }
            break;
        case EaseRecordViewTypeTouchUpInside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonTouchUpInside];
            }
            [self.recordView removeFromSuperview];
        }
            break;
        case EaseRecordViewTypeTouchUpOutside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonTouchUpOutside];
            }
            [self.recordView removeFromSuperview];
        }
            break;
        case EaseRecordViewTypeDragInside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonDragInside];
            }
        }
            break;
        case EaseRecordViewTypeDragOutside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonDragOutside];
            }
        }
            break;
        default:
            break;
    }
}

EaseMessageViewControllerDataSource

用户判断消息是否允许长按,返回布尔值;如果用户允许长按,此方法为通知用户触发长按手势,返回布尔值,如果返回 NO 默认方式处理,返回 YES 采用用户自定义的处理方式。

/*!
 @method
 @brief 是否允许长按
 @discussion 获取是否允许长按的回调,默认是NO
 @param viewController 当前消息视图
 @param indexPath 长按消息对应的indexPath
 @result
 */
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   canLongPressRowAtIndexPath:(NSIndexPath *)indexPath;

/*!
 @method
 @brief 触发长按手势
 @discussion 获取触发长按手势的回调,默认是NO
 @param viewController 当前消息视图
 @param indexPath 长按消息对应的indexPath
 @result
 */
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   didLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
   
//长按收拾回调样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   canLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
    //样例给出的逻辑是所有cell都允许长按
    return YES;
}

- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   didLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
    //样例给出的逻辑是长按cell之后显示menu视图
    id object = [self.dataArray objectAtIndex:indexPath.row];
    if (![object isKindOfClass:[NSString class]]) {
        EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        [cell becomeFirstResponder];
        self.menuIndexPath = indexPath;
        [self _showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType];
    }
    return YES;
}

Demo3.0实现的消息长按效果演示:

Demo3.0实现的消息长按效果演示

将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像。

/*!
 @method
 @brief 将EMMessage类型转换为符合<IMessageModel>协议的类型
 @discussion 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像
 @param viewController 当前消息视图
 @param EMMessage 聊天消息对象类型
 @result 返回<IMessageModel>协议的类型
 */
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
                           modelForMessage:(EMMessage *)message;
                           
//具体样例:
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
                           modelForMessage:(EMMessage *)message
{
    //用户可以根据自己的用户体系,根据message设置用户昵称和头像
    id<IMessageModel> model = nil;
    model = [[EaseMessageModel alloc] initWithMessage:message];
    model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
    model.avatarURLPath = @"";//头像网络地址
    model.nickname = @"昵称";//用户昵称
    return model;
}

聊天会话页面头像和昵称的效果演示:

聊天会话页面头像和昵称的效果演示

聊天会话样式自定义

聊天样式的自定义需要在 EaseMessageViewController 中 viewDidload 结束前设置。
@property中带有UI_APPEARANCE_SELECTOR,都可以通过set的形式设置样式,具体可以参考EaseBaseMessageCell.h,EaseMessageCell.h

发送气泡图片设置

[[EaseBaseMessageCell appearance] setSendBubbleBackgroundImage:[[UIImage imageNamed:@"chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]];//设置发送气泡

[[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage imageNamed:@"chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]];//设置接收气泡

头像设置

[[EaseBaseMessageCell appearance] setAvatarSize:40.f];//设置头像大小

[[EaseBaseMessageCell appearance] setAvatarCornerRadius:20.f];//设置头像圆角

消息字体颜色设置

[[EaseMessageCell appearance] setMessageTextFont:[UIFont systemFontOfSize:15]];//消息显示字体

[[EaseMessageCell appearance] setMessageTextColor:[UIColor blackColor]];//消息显示颜色

[[EaseMessageCell appearance] setMessageLocationFont:[UIFont systemFontOfSize:12]];//位置消息显示字体

[[EaseMessageCell appearance] setMessageLocationColor:[UIColor whiteColor]];//位置消息显示颜色

语音消息图片样式设置

[[EaseBaseMessageCell appearance] setSendMessageVoiceAnimationImages:@[[UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_full"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_000"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_001"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_002"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_003"]]];//发送者语音消息播放图片

[[EaseBaseMessageCell appearance] setRecvMessageVoiceAnimationImages:@[[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing_full"],[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing000"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing001"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing002"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing003"]]];//接收者语音消息播放图片

聊天会话输入框自定义

继承EaseMessageViewController,或者EaseMessageViewController的实例调用以下方法设置底部输入框

CustomerInputView *inputView = [[CustomerInputView alloc] init];//CustomerInputView用户自定义底部输入框
[self setChatToolbar:inputView];

实现默认底部输入框delegate

@interface CustomerInputView : UIView

@property (weak, nonatomic) id<EMChatToolbarDelegate> delegate;

@end

自定义输入框发送消息

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    if ([text isEqualToString:@"\n"]){
        if(self.delegate && [self.delegate respondsToSelector:@selector(didSendText:)]) {
            [self.delegate didSendText:self.textView.text];
        }
        self.textView.text = @"";
        self.placeholderLabel.text = @"说点什么吧...";
        return NO;
    }
    return YES;
}

自定义输入框高度变化

//这是一个举例,初始化输入框的时候注册监听键盘高度变化
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotification object:nil];

- (void)keyboardWillShow:(NSNotification *)aNotification{
    //获取键盘的高度
    NSValue *aValue = [[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardRect = [aValue CGRectValue];
    if (keyboardRect.size.height > self.keyboardHeight) {
        self.keyboardHeight = keyboardRect.size.height;
    }
    self.frame = CGRectMake(0, _originY - self.keyboardHeight - 64, App_Width, self.inputH + self.keyboardHeight);
    if (self.delegate && [self.delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) {
        [self.delegate chatToolbarDidChangeFrameToHeight:self.frame.size.height];
    }
}

- (void)keyboardWillHide:(NSNotification *)aNotification{
    self.frame = CGRectMake(0, _originY - 64, App_Width, self.inputH) ;
    if (self.delegate && [self.delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) {
        [self.delegate chatToolbarDidChangeFrameToHeight:self.frame.size.height];
    }
}

聊天会话底部菜单自定义

EaseChatBarMoreView为自定义的功能菜单选择视图,目前已添加的功能有:

/*!
 @method
 @brief 新增一个新的功能按钮
 @discussion
 @param image 按钮图片
 @param highLightedImage 高亮图片
 @param title 按钮标题
 @result
 */
- (void)insertItemWithImage:(UIImage*)image
           highlightedImage:(UIImage*)highLightedImage
                      title:(NSString*)title;

/*!
 @method
 @brief 修改功能按钮图片
 @discussion
 @param image 按钮图片
 @param highLightedImage 高亮图片
 @param title 按钮标题
 @param index 按钮索引
 @result
 */
- (void)updateItemWithImage:(UIImage*)image
           highlightedImage:(UIImage*)highLightedImage
                      title:(NSString*)title
                    atIndex:(NSInteger)index;

/*!
 @method
 @brief 根据索引删除功能按钮
 @discussion
 @param index 按钮索引
 @result
 */
- (void)removeItematIndex:(NSInteger)index;

各个选项的功能需要ViewController实现EaseChatBarMoreViewDelegate协议中的回调方法来编写或调整.

EaseSDKHelper 封装了发送消息的方法。

具体发送消息样例:

/*
 EMChatTypeChat            单聊消息
 EMChatTypeGroupChat       群聊消息
 EMChatTypeChatRoom        聊天室消息
*/

//发送文字消息
EMMessage *message = [EaseSDKHelper sendTextMessage:@"要发送的消息"
                                                 to:@"6001"//接收方
                                        messageType:EMChatTypeChat//消息类型
                                         messageExt:nil]; //扩展信息                                          
//发送位置消息
EMMessage *message = [EaseSDKHelper sendLocationMessageWithLatitude:35.1//经度
                                                          longitude:35.1//纬度
                                                            address:"地址"
                                                                 to:@"6001"//接收方
                                                        messageType:EMChatTypeChat//消息类型
                                                         messageExt:nil];//扩展信息                                         

//发送图片消息      
EMMessage *message = [EaseSDKHelper sendImageMessageWithImageData:imageData//发送的图片数据NSData
                                                               to:@"6001"//接收方
                                                      messageType:EMChatTypeChat//消息类型
                                                       messageExt:nil];//扩展信息                                                    

//发送音频消息                                           
EMMessage *message = [EaseSDKHelper sendVoiceMessageWithLocalPath:localPath//音频本地地址
                                                         duration:duration//语音的时长,单位是秒
                                                               to:@"6001"//接收方
                                                      messageType:EMChatTypeChat//消息类型
                                                       messageExt:nil];//扩展信息

//发送视频文件消息
EMMessage *message = [EaseSDKHelper sendVideoMessageWithURL:url//发送的视频地址
                                                         to:@"6001"//接收方
                                                messageType:EMChatTypeChat//消息类型
                                                 messageExt:nil];//扩展信息

//发送构造成功的消息                                                   
[[EMClient sharedClient].chatManager asyncSendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {

}];                                                                                                                                                                                                                                                   

会话列表初始化

EaseConversationListViewController *chatListVC = [[EaseConversationListViewController alloc] init];

会话列表下拉刷新

需要继承EaseConversationListViewController的子类,在viewDidLoad中加入

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshHeader = YES;
    //首次进入加载数据
    [self tableViewDidTriggerHeaderRefresh];
}

会话列表扩展

EaseConversationListViewControllerDataSource

用户根据 conversationModel 实现,实现自定义会话中最后一条消息文案的显示内容。

/*!
 @method
 @brief 获取最后一条消息显示的内容
 @discussion 用户根据conversationModel实现,实现自定义会话中最后一条消息文案的显示内容
 @param conversationListViewController 当前会话列表视图
 @param IConversationModel 会话模型
 @result 返回用户最后一条消息显示的内容
 */
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
      latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel;


/*!
 @method
 @brief 获取最后一条消息显示的时间
 @discussion 用户可以根据conversationModel,自定义实现会话列表中时间文案的显示内容
 @param conversationListViewController 当前会话列表视图
 @param IConversationModel 会话模型
 @result 返回用户最后一条消息时间的显示文案
 */
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
       latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel;
       
//最后一条消息展示内容样例    
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
      latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel
{
    NSString *latestMessageTitle = @"";
    EMMessage *lastMessage = [conversationModel.conversation latestMessage];
    if (lastMessage) {
        EMMessageBody *messageBody = lastMessage.body;
        switch (messageBody.type) {
            case EMMessageBodyTypeImage:{
                latestMessageTitle = NSLocalizedString(@"message.image1", @"[image]");
            } break;
            case EMMessageBodyTypeText:{
                // 表情映射。
                NSString *didReceiveText = [EaseConvertToCommonEmoticonsHelper
                                            convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text];
                latestMessageTitle = didReceiveText;
                if ([lastMessage.ext objectForKey:MESSAGE_ATTR_IS_BIG_EXPRESSION]) {
                    latestMessageTitle = @"[动画表情]";
                }
            } break;
            case EMMessageBodyTypeVoice:{
                latestMessageTitle = NSLocalizedString(@"message.voice1", @"[voice]");
            } break;
            case EMMessageBodyTypeLocation: {
                latestMessageTitle = NSLocalizedString(@"message.location1", @"[location]");
            } break;
            case EMMessageBodyTypeVideo: {
                latestMessageTitle = NSLocalizedString(@"message.video1", @"[video]");
            } break;
            case EMMessageBodyTypeFile: {
                latestMessageTitle = NSLocalizedString(@"message.file1", @"[file]");
            } break;
            default: {
            } break;
        }
    }
    
    return latestMessageTitle;
}

//最后一条消息展示时间样例  
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
       latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel
{
    NSString *latestMessageTime = @"";
    EMMessage *lastMessage = [conversationModel.conversation latestMessage];;
    if (lastMessage) {
        latestMessageTime = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp];
    }
    return latestMessageTime;
}

会话列表最后一条消息和时间显示的效果演示:

会话列表最后一条消息和时间显示的效果演示

EaseConversationListViewControllerDelegate

点击会话列表用户可以根据 conversationModel 自定义处理逻辑。

/*!
 @method
 @brief 获取点击会话列表的回调
 @discussion 获取点击会话列表的回调后,点击会话列表用户可以根据conversationModel自定义处理逻辑
 @param conversationListViewController 当前会话列表视图
 @param IConversationModel 会话模型
 @result
 */
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
            didSelectConversationModel:(id<IConversationModel>)conversationModel;
            
//会话列表点击的回调样例
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
            didSelectConversationModel:(id<IConversationModel>)conversationModel
{
    //样例展示为根据conversationModel,进入不同的会话ViewController
        if (conversationModel) {
        EMConversation *conversation = conversationModel.conversation;
        if (conversation) {
            if ([[RobotManager sharedInstance] isRobotWithUsername:conversation.conversationId]) {
                RobotChatViewController *chatController = [[RobotChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
                chatController.title = [[RobotManager sharedInstance] getRobotNickWithUsername:conversation.conversationId];
                [self.navigationController pushViewController:chatController animated:YES];
            } else {
                ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
                chatController.title = conversationModel.title;
                [self.navigationController pushViewController:chatController animated:YES];
            }
        }
        [[NSNotificationCenter defaultCenter] postNotificationName:@"setupUnreadMessageCount" object:nil];
        [self.tableView reloadData];
    }
}

联系人列表初始化

EaseUsersListViewController *listViewController = [[EaseUsersListViewController alloc] init];

联系人列表下拉刷新

需要继承EaseUsersListViewController的子类,在viewDidLoad中加入

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshHeader = YES;
}

联系人列表扩展

需要实现 EMUserListViewControllerDataSource。

根据 buddy 获取用户自定信息,联系人列表里展示昵称和头像。

/*!
 @method
 @brief 获取用户模型
 @discussion 根据buddy获取用户自定信息,联系人列表里展示昵称和头像
 @param userListViewController 当前联系人视图
 @param buddy 好友的信息描述类
 @result 返回用户模型
 */
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
                           modelForBuddy:(NSString *)buddy;
                           
//联系人列表扩展样例
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
                           modelForBuddy:(NSString *)buddy
{
    //用户可以根据自己的用户体系,根据buddy设置用户昵称和头像
    id<IUserModel> model = nil;
    model = [[EaseUserModel alloc] initWithBuddy:buddy];
    model.avatarURLPath = @"";//头像网络地址
    model.nickname = @"昵称";//用户昵称
    return model;
}

联系人列表头像和昵称的效果演示:

联系人列表头像和昵称的效果演示

  • MBProgressHUD
  • MJRefresh
  • MWPhotoBrowser
  • SDWebImage
  • DACircularProgressView

EaseUI中第三方库冲突问题

目前推荐Pod的方式集成EaseUI。如果集成了EaseUI,而且上述第三方依赖在开发者的代码中也有引用,会造成冲突,无法编译,针对此问题有如下两种场景:

  • 开发者使用的第三方依赖也是通过pod方式集成,这样pod只会安装一份,不会重复安装多个版本。如果是依赖版本不兼容,例如开发者依赖了'MBProgressHUD', '~> 1.0.0' ,而EaseUI通过MWPhotoBrowser间接依赖了'MBProgressHUD', '~> 0.9' ,这样会导致pod install失败,开发者可以改变MBProgressHUD的依赖版本。EaseUI也会在后续版本中尽量减少使用第三方依赖。
  • 如果是手动导入了上述第三方库,建议直接删除手动导入的部分,避免冲突的产生,如果EaseUI使用第三方库的版本不能满足开发者的需求,开发者也可以手动将第三方库进行重命名,保证兼容(手动方式集成EaseUI也可以参考此解决方案)。