融云IMKit的简单使用

写在前面
融云是一个比较强大的第三方框架,为我们提供了即时通讯的基本组件,导入SDK,进行一些简单的配置就可以看到会话列表,会话界面,为我们省去了很多工作(IMKit)。IMKit对于要求不是很高,不需要很多自定义(也就是很多奇形怪状的东西)的产品来说已经够用了。
下面是我使用到的IMKit的一些简单功能,做一下分享。

在使用之前,当然需要一个应用,这不需要多说了,去注册一个融云开发者账号,然后创建一个应用吧。

屏幕快照 2016-11-04 上午11.56.58.png

0.导入SDK
有两种方式可以将 SDK 导入您的项目中:
通过 CocoaPods
管理依赖;
手动导入 SDK
并管理依赖;

CocoaPods 是目前最流行的 Cocoa
项目库依赖管理工具之一,考虑到便捷与项目的可维护性,我们更推荐您使用 CocoaPods
导入并管理 SDK。
使用 CocoaPods 导入 SDK
1、 CocoaPods 安装
如果您的机器上已经安装了 CocoaPods
,直接进入下一步即可。
如果您的网络已经翻墙,在终端中运行如下命令直接安装:
sudo gem install cocoapods

如果您的网络不能翻墙,可以通过淘宝的 RubyGems镜像 进行安装。在终端依次运行以下命令:
gem sources --add https://ruby.taobao.org/ --remove https://rubygems.org/sudo gem install cocoapods

2、 查询 CocoaPods
源中的融云 SDK
在终端中运行以下命令:
pod search RongCloudIM

image

命令截图
您可以看到,融云在 CocoaPods 上提供了三种 SDK 下载,IMLib
、不包含VoIP功能的 IMKit
、包含 VoIP 功能的 IMKit
,您按照您的需求安装选择其中一个即可。
如果运行以上命令,没有搜到融云的 SDK 或者搜不到最新的 SDK 版本,您可以运行以下命令,更新一下您本地的 CocoaPods 源列表。
pod repo update

3、 使用 CocoaPods 导入融云 SDK
在您的工程根目录下新建一个 Podfile 文件,在文件中输入以下内容。(在此以 2.4.0 版本为例,其中 “MyApp” 为自己工程名)
target 'MyApp' dopod 'RongCloudIMKit', '2.4.0'end

然后在终端中运行以下命令:
pod install

完成后,CocoaPods 会在您的工程根目录下生成一个 .xcworkspace
文件。您需要通过此文件打开您的工程,而不是之前的 .xcodeproj

请不要在 Podfile
中同时引用 IMKit 和 IMLib,因为 CocoaPods
中的 IMKit 包中已经包含了 IMLib 的内容,重复引用会导致无法正常编译。
CocoaPods 使用说明
指定 SDK 版本
CocoaPods
中,有几种设置 SDK 版本的方法。如:
'>= 2.4.X' 会根据您本地的 CocoaPods 源列表,导入不低于 2.4.X
版本的 SDK。
'~> 2.4.X' 会根据您本地的 CocoaPods 源列表,介于 2.4.X~2.5.0
之前版本的 SDK。

我们建议您锁定版本,便于团队开发。如,指定 2.4.X
版本。
pod 'RongCloudIMKit', '2.4.X'

升级工程的 SDK 版本
更新您工程目录中 Podfile 指定的 SDK 版本后,在终端中执行以下命令。
pod update

清除 CocoaPods 本地缓存
特殊情况下,由于网络或者别的原因,通过 CocoaPods
下载的文件可能会有问题。
这时候您可以删除 CocoaPods
的缓存(~/Library/Caches/CocoaPods/Pods/Release
目录),再次导入即可。
查看当前使用的 SDK 版本
您可以在 Podfile.lock
文件中看到您工程中使用的 SDK 版本。

这是我直接贴的融云开发文档,很简单咯。

手动导入:

屏幕快照 2016-11-04 下午12.02.19.png

就是这个文件夹了,拖到你的工程里,就这么简单。
还有一些简单的配置:
---添加系统依赖库
AssetsLibrary.framework
AudioToolbox.framework
AVFoundation.framework
CFNetwork.framework
CoreAudio.framework
CoreGraphics.framework
CoreLocation.framework
CoreMedia.framework
CoreTelephony.framework
CoreVideo.framework
ImageIO.framework
libc++.tbd
libc++abi.tbd
libsqlite3.tbd
libstdc++.tbd
libxml2.tbd
libz.tbd
MapKit.framework
OpenGLES.framework
QuartzCore.framework
SystemConfiguration.framework
UIKit.framework
Photos.framework
有点多,耐心点吧。

---在 Xcode 项目 Build Settings -> Other Linker Flags 中,增加"-ObjC"。

--- 设置 App 支持 http
iOS 9 中,Apple 引入了新特性 App Transport Security (ATS)
,默认要求 App 必须使用 https 协议。详情:What's New in iOS 9.0
融云 SDK 在 iOS9 上需要使用 http,您需要设置在 App 中使用 http。
在 App 的 Info.plist
中添加 NSAppTransportSecurity 类型Dictionary。
在 NSAppTransportSecurity下添加 NSAllowsArbitraryLoads 类型 Boolean,值设为 YES。

好了,导入成功,配置完成!

1.登录融云
---初始化
在你需要使用融云 SDK 功能的类中,import 相关头文件。

#import <RongIMKit/RongIMKit.h>

如果是 Swift 的话,需要在你工程的 Bridging-Header.h文件中加入 SDK 的引用。

#import <RongIMKit/RongIMKit.h>

之前从融云开发者控制台注册得到的 App Key,现在要用上了。
Objective-C 代码

[[RCIM sharedRCIM] initWithAppKey:@"YourTestAppKey"];

Swift 代码

RCIM.sharedRCIM().initWithAppKey("YourTestAppKey")

--- 获取token
必须在服务器端请求 Token,因为获取 Token 时需要提供 App Key 和 App Secret。如果在客户端请求 Token,假如 App 代码一旦被反编译,则会导致 App Key和App Secret 泄露。
这一步就要向你自己的服务端请求token了,这个服务端的同学会做好,然后给你一个接口,你去请求就OK了。不多说。
调试阶段,服务端的同学还没写好接口,所以就先弄个假的吧

屏幕快照 2016-11-04 下午2.03.40.png

这个API调试,获取token

屏幕快照 2016-11-04 下午2.12.17.png

这下面填上用户ID和昵称就提交就获取到了。

---连接融云服务器
获取token成功后,就可以用这个token连接融云服务器了,So easy!
Objective-C 代码

[[RCIM sharedRCIM] connectWithToken:@"YourTestUserToken" success:^(NSString *userId) { 
NSLog(@"登陆成功。当前登录的用户ID:%@", userId);
} error:^(RCConnectErrorCode status) {
 NSLog(@"登陆的错误码为:%d", status);
} tokenIncorrect:^{
 //token过期或者不正确。 
//如果设置了token有效期并且token过期,请重新请求您的服务器获取新的token
//如果没有设置token有效期却提示token错误,请检查您客户端和服务器的appkey是否匹配,还有检查您获取token的流程。 
NSLog(@"token错误");
}];

Swift代码

RCIM.sharedRCIM().connectWithToken("YourTestUserToken",success: { (userId) -> Void in 
print("登陆成功。当前登录的用户ID:\(userId)")
}, error: { (status) -> Void in 
print("登陆的错误码为:\(status.rawValue)")
}, tokenIncorrect: { 
//token过期或者不正确。 
//如果设置了token有效期并且token过期,请重新请求您的服务器获取新的token 
//如果没有设置token有效期却提示token错误,请检查您客户端和服务器的appkey是否匹配,还有检查您获取token的流程。 
print("token错误")
})

一般登录操作写在AppDelegate里面就可以了,在登陆成功后如果要跳转到某个控制器的话,记得回到主线程哦,不然会很卡很卡

 // 在主线程更新UI
dispatch_sync(dispatch_get_main_queue(), ^(){
               // 就是这里去跳转啊,刷新UI啊!
            });

2.会话列表
用IMKit,就是简单到不要不要的,直接用RCConversationListViewController 或者继承它创建一个控制器一个列表就出现了。我是继承RCConversationListViewController创建了一个控制器,再设置一些属性就OK了。
Objective-C 代码:

//重写显示相关的接口,必须先调用super,否则会屏蔽SDK默认的处理 
[super viewDidLoad]; 
//设置需要显示哪些类型的会话,会话类型有很多,选择你需要的就好啦
[self setDisplayConversationTypes:@[@(ConversationType_PRIVATE), @(ConversationType_DISCUSSION), @(ConversationType_CHATROOM), @(ConversationType_GROUP), @(ConversationType_APPSERVICE), @(ConversationType_SYSTEM)]]; //设置需要将哪些类型的会话在会话列表中聚合显示 
[self setCollectionConversationType:@[@(ConversationType_DISCUSSION), @(ConversationType_GROUP)]];}

Swift 代码:

//重写显示相关的接口,必须先调用super,否则会屏蔽SDK默认的处理 
super.viewDidLoad() 
//设置需要显示哪些类型的会话 
self.setDisplayConversationTypes([RCConversationType.ConversationType_PRIVATE.rawValue, RCConversationType.ConversationType_DISCUSSION.rawValue, RCConversationType.ConversationType_CHATROOM.rawValue, RCConversationType.ConversationType_GROUP.rawValue, RCConversationType.ConversationType_APPSERVICE.rawValue, RCConversationType.ConversationType_SYSTEM.rawValue])
//设置需要将哪些类型的会话在会话列表中聚合显示 
self.setCollectionConversationType([RCConversationType.ConversationType_DISCUSSION.rawValue, RCConversationType.ConversationType_GROUP.rawValue])

就是这么简单, 一个会话列表就设置好了,当然是很原生态的了.
会话列表嘛,肯定要显示用户名、昵称和头像的,userInfoDataSource 和 groupMemberDataSource两个代理会为我们完美的解决显示用户信息的问题。
设置代理:

[RCIM sharedRCIM].userInfoDataSource = AppDelegate;
[RCIM sharedRCIM].groupMemberDataSource = AppDelegate;

实现代理方法:

- (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *))completion {
    NSLog(@"Rong cloud userID: %@", userId);
    RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:userId
                                                     name:userName
                                                 portrait:userPortrait];
        return completion(user);
}

当需要显示用户信息的时候,IMKit自己会走这个方法去查询用户信息,然后显示在适当的位置。
不要傻傻的像上面那么写,然后还问怎么没显示,当然不显示了,用户的信息融云的服务器不会帮你存的,在这里要去请求自己的服务器,根据userID查到用户的信息然后赋值 ,return completion(user);

去融云控制台调试一下吧,还是那个API调试,

屏幕快照 2016-11-04 下午2.04.38.png

在下面填上发送者的ID,接收者的ID,发几条试试,收到消息的感觉有没有很爽~


要做一些实质性的工作了!
我们这个项目呢,需要在消息列表的页面顶端做一个通知的cell,它永远置顶,SDK原生的列表当然没有这个了,还好,是置顶的。
列表嘛,当然还是个tableView,tableView的所有控件当然还在,所以这个置顶的cell简单了,做成headerView 就OK啦!

@interface ConversationListVC ()

@property (nonatomic, strong) ConversationListHeaderView *tableHeaderView;

@end
- (UIView *)tableHeaderView {
    if (!_tableHeaderView) {
        _tableHeaderView = [[ConversationListHeaderView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, SCALE6P(206))];        
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(headerViewTapped:)];
        [_tableHeaderView addGestureRecognizer:tap];
    }
    return _tableHeaderView;
}

ConversationListHeaderView 这是我自己写的一个view啦,不用在贴代码了哦!

    self.conversationListTableView.tableHeaderView = self.tableHeaderView; //设置tableView头部
    self.conversationListTableView.tableFooterView = [UIView new];//这样就不会显示多余的分割线啦
    self.conversationListTableView.backgroundColor = [UIColor clearColor];// 背景色嘛,clearColor尽量不要用哦,为什么?自行百度!
    self.conversationListTableView.layoutMargins = UIEdgeInsetsZero;
    self.conversationListTableView.separatorInset = UIEdgeInsetsZero;
    self.topCellBackgroundColor = [UIColor blueColor]; // 置顶的消息背景颜色,不设置的话会有淡淡的蓝色

上面是对“conversationListTableView”的一些设置,这时候会话列表会看起来更舒服一些。
刚刚提到了置顶,当然还会有标为已读,标为未读,删除这些需求了,怎么办?tableView嘛,直接去实现代理方法就好了

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    RCConversationModel *model = self.conversationListDataSource[indexPath.row];
    UITableViewRowAction *deleteRoWAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
        
        [[RCIMClient sharedRCIMClient] removeConversation:ConversationType_PRIVATE targetId:model.targetId];
        [self refreshConversationTableViewIfNeeded];
        
    }];
    UITableViewRowAction *readRoWAction;
    if (model.unreadMessageCount > 0) {
        readRoWAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"标为已读" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
            [[RCIMClient sharedRCIMClient] clearMessagesUnreadStatus:ConversationType_PRIVATE targetId:model.targetId];
            
            [self refreshConversationTableViewIfNeeded];
        }];
    } else {
        readRoWAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"标为未读" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
            [[RCIMClient sharedRCIMClient] setMessageReceivedStatus:model.lastestMessageId receivedStatus:ReceivedStatus_UNREAD];
            [self refreshConversationTableViewIfNeeded];// 刷新tableView
        }];
    }
    UITableViewRowAction *topRoWAction;
    if (model.isTop) {
        topRoWAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"取消置顶" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
            [[RCIMClient sharedRCIMClient] setConversationToTop:1 targetId:model.targetId isTop:NO];
            [self refreshConversationTableViewIfNeeded];
        }];
        topRoWAction.backgroundColor = HighlightColor;// 设置成你喜欢的颜色
    } else {
        topRoWAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"置顶" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
            [[RCIMClient sharedRCIMClient] setConversationToTop:1 targetId:model.targetId isTop:YES];
            [self refreshConversationTableViewIfNeeded];
        }];
        topRoWAction.backgroundColor = HighlightColor;
    }
    return @[deleteRoWAction, readRoWAction, topRoWAction];
}

我做的好像有点简单粗暴,哪位有好方法要告诉我哦!

--- 改变一下cell的样子,我们这个基本没改变什么,只是置顶的时候我们需要一个小标志,我就在这里直接改了

- (void)willDisplayConversationTableCell:(RCConversationBaseCell *)cell atIndexPath:(NSIndexPath *)indexPath {//cell将要显示的时候会走这里,在这里做一些微调当然是可以的了,一定要注意要写 super *******
    [super willDisplayConversationTableCell:cell atIndexPath:indexPath];
    
    RCConversationModel *model = self.conversationListDataSource[indexPath.row];
    //    NSLog(@"title : %@", model.conversationTitle);
    
    RCConversationCell *conversationCell = (RCConversationCell *)cell;
    cell.layoutMargins = UIEdgeInsetsZero;
    
    // 置顶设置
    if (model.isTop) {
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - SCALE6P(39), 0, SCALE6P(39), SCALE6P(45))];
        imageView.image = [UIImage imageNamed:@"Top_trangle_image"];
        imageView.tag = TOP_CONVERSATION_IMAGE_VIEW_TAG;
        [conversationCell.contentView addSubview:imageView];
    }
    
    RCUserInfo *userInfo = [[RCIM sharedRCIM] getUserInfoCache:model.targetId];
    
    for (UIView *view in conversationCell.contentView.subviews) {
        // 这里改了一下下字体哦~
        if ([view isKindOfClass:UILabel.class]) {
            UILabel *label = (UILabel *)view;
            label.font = MainFontOfSize(label.font.pointSize);
            if (label.x < conversationCell.contentView.width / 2) {
                if (label.y < conversationCell.contentView.height / 3) {
                    label.textColor = LabelTextDarkGrayColor;
                    label.font = MainFontOfSize(SCALE6P(40));
                } else {
                    label.textColor = LabelTextLightGrayColor;
                    label.font = MainFontOfSize(SCALE6P(34));
                }
            } else {
                label.textColor = LabelTextLightGrayColor;
                label.font = MainFontOfSize(SCALE6P(32));
            }
        }
        // 非置顶设置
        if (!model.isTop && [view isKindOfClass:UIImageView.class] && view.tag == TOP_CONVERSATION_IMAGE_VIEW_TAG) {
            [view removeFromSuperview];
        }
    }
    [cell layoutIfNeeded];
}
/*!
 在会话列表中,收到新消息的回调
 
 @param notification    收到新消息的notification
 
 @discussion SDK在此方法中有针对消息接收有默认的处理(如刷新等),如果您重写此方法,请注意调用super。
 
 notification的object为RCMessage消息对象,userInfo为NSDictionary对象,其中key值为@"left",value为还剩余未接收的消息数的NSNumber对象。
 */
- (void)didReceiveMessageNotification:(NSNotification *)notification {
    [super didReceiveMessageNotification:notification];
}
/*!
 点击Cell头像的回调
 
 @param model   会话Cell的数据模型
 */
- (void)didTapCellPortrait:(RCConversationModel *)model {
    
}

/*!
 长按Cell头像的回调
 
 @param model   会话Cell的数据模型
 */
- (void)didLongPressCellPortrait:(RCConversationModel *)model {
    
}
/*!
 点击会话列表中Cell的回调
 
 @param conversationModelType   当前点击的会话的Model类型
 @param model                   当前点击的会话的Model
 @param indexPath               当前会话在列表数据源中的索引值
 
 @discussion 您需要重写此点击事件,跳转到指定会话的聊天界面。
 如果点击聚合Cell进入具体的子会话列表,在跳转时,需要将isEnteredToCollectionViewController设置为YES。
 */
- (void)onSelectedTableRow:(RCConversationModelType)conversationModelType
         conversationModel:(RCConversationModel *)model
               atIndexPath:(NSIndexPath *)indexPath {
ConversationVC *conversationVC = [[ConversationVC alloc] init];
    conversationVC.conversationType = model.conversationType;
    conversationVC.targetId = model.targetId;
    
    conversationVC.navigationItem.title = model.conversationTitle;
    [self.navigationController pushViewController:conversationVC animated:YES]; // 进入聊天界面了
    
    [self.conversationListTableView cellForRowAtIndexPath:indexPath].selected = NO;
}

还有一些小设置,更简单了 直接到头文件里看一看,都是中文,一目了然,这里就不多说了~

3.会话界面
要发送消息了 就要去聊天界面了,这里更是So easy!
上面点击会话列表cell的回调中进入的那个聊天界面,就是继承RCConversationViewController 的一个控制器——ConversationVC,甚至什么都不用做,就这么push进来了!就可以发消息了!就可以看到收到的消息了!(此时感叹融云SDK的开发者们真的都是神级的任务啊)

/*!
 输入框中内容发生变化的回调
 
 @param inputTextView 文本输入框
 @param range         当前操作的范围
 @param text          插入的文本
 */
- (void)inputTextView:(UITextView *)inputTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    [super inputTextView:inputTextView shouldChangeTextInRange:range replacementText:text];
    
}

/*!
 扩展功能板的点击回调
 
 @param pluginBoardView 输入扩展功能板View
 @param tag             输入扩展功能(Item)的唯一标示
 */
- (void)pluginBoardView:(RCPluginBoardView*)pluginBoardView clickedItemWithTag:(NSInteger)tag {
    [super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
   
}

/*!
 开始录制语音消息的回调
 */
- (void)onBeginRecordEvent {
    [super onBeginRecordEvent];
    
}
#pragma mark 点击头像
- (void)didTapCellPortrait:(NSString *)userId {
  
}
#pragma mark 点击头像
- (void)didLongPressCellPortrait:(NSString *)userId {

}
/*!
 点击Cell中URL的回调
 
 @param url   点击的URL
 @param model 消息Cell的数据模型
*/
- (void)didTapUrlInMessageCell:(NSString *)url
                         model:(RCMessageModel *)model;

/*!
 点击Cell中电话号码的回调
 
 @param phoneNumber 点击的电话号码
 @param model       消息Cell的数据模型
 */
- (void)didTapPhoneNumberInMessageCell:(NSString *)phoneNumber
                                 model:(RCMessageModel *)model;

不贴代码了,进入头文件看一吧,基本功能都能实现了。

4.消息缓存
刚刚用了IMKit不久,一直不知道缓存去哪了,怎么才能在断网的时候显示聊天记录呢?
当然不用,自己去写缓存啦,SDK为我们做好了,怎么显示?
还记得连接融云服务器的方法么?
在我们服务端获取token成功之后我们会去连接融云的服务器,断网的时候当然我们不能获取到token了。
我们需要在获取token成功之后缓存一下这个token,

[NSUserDefaults standardUserDefaults] setObject:token forKey:KRongCloudToken];

再次登录的时候,如果获取token失败了,那在登录失败的方法中用缓存的token连接融云服务器,

[[RCIM sharedRCIM] connectWithToken:KRongCloudToken success:^(NSString *userId) { 
NSLog(@"登陆成功。当前登录的用户ID:%@", userId);
} error:^(RCConnectErrorCode status) { 
NSLog(@"登陆的错误码为:%d", status);
} tokenIncorrect:^{  
NSLog(@"token错误");
}];

不要怀疑,写上这一段代码,然后呢 缓存消息没出现啊。。。。
当然不会出现,要告诉SDK取哪个用户的缓存信息啊!

 [[RCIM sharedRCIM] connectWithToken:KRongCloudToken success:^(NSString *userId) {
            [RCIM sharedRCIM].userInfoDataSource = (id<RCIMUserInfoDataSource>)[UIApplication sharedApplication].delegate;
            RCUserInfo *currentUserInfo = [[RCUserInfo alloc] initWithUserId:model.userID
                                                                        name:[model acquireParentBabyName]
                                                                    portrait:model.userHeadImage];
            [RCIM sharedRCIM].currentUserInfo = currentUserInfo;//告诉SDK当前是哪个用户登录就好了,用户信息是你之前缓存的哦~
        } error:^(RCConnectErrorCode status) {
        } tokenIncorrect:^{
        }];

此时,缓存的聊天消息在断网的情况下也出现了,但是看着很别扭,只有聊得记录,却不显示用户的头像和昵称,别担心,你看到这篇分享的时候下载的SDK版本已经做好了用户信息的缓存,在AppDelegate里面设置一下就看到完整的信息了

    [RCIM sharedRCIM].enablePersistentUserInfoCache = YES;

缓存就这些吧,其实什么都不用做,设置一下就好了~

5.消息推送
收到消息之后要通知用户啊,这就需要远程推送了。
不知道你的项目之前有没有用到其他的推送,我们的项目在做聊天之前用了极光推送。极光推送和聊天消息推送是不冲突的,一起存在当然没问题。
如果你的项目之前没有做远程推送,那么就需要先去开发者账号中申请推送证书了,怎么申请?这个。。。自行百度吧,融云的文档中也有,很详细。

屏幕快照 2016-11-04 下午3.18.43.png

上传好证书,在AppDelegate中设置一下就OK~
码这么多字,,,不想码了直接去文档看吧,真的很详细!
具体可以参考远程推送文档


结尾~
一些小设置~

    [RCIM sharedRCIM].globalConversationAvatarStyle = RC_USER_AVATAR_CYCLE; // 列表页头像的形状,我设置成了圆形
[RCIM sharedRCIM].globalConversationPortraitSize// 列表页头像的大小,默认是46*46

[RCIM sharedRCIM].globalMessageAvatarStyle // 聊天界面头像的形状
[RCIM sharedRCIM].globalMessagePortraitSize // 聊天界面头像的大小默认是40*40


self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"Arrow_back_white"] style:UIBarButtonItemStylePlain target:self action:@selector(returnBtnTapped:)];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Clear_all_messages"] style:UIBarButtonItemStylePlain target:self action:@selector(clearAllMessage:)];  
    [self.navigationController.navigationBar setBackgroundImage:[CommonTool imageWithColor:ThemeColor] forBarMetrics:UIBarMetricsDefault];//这都是系统方法喽

还有发送位置和发送照片的时候navigation的颜色有点不太对,我是在AppDelegate里面统一设置的

[[UINavigationBar appearance] setBarTintColor:ThemeColor];
    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
    [[UINavigationBar appearance] setTitleTextAttributes:@{ NSForegroundColorAttributeName : [UIColor whiteColor], NSFontAttributeName : “YouFont”}];

码了半个下午,以后遇到什么了会继续补充~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • 相信大家在项目中会用到即时通讯功能,自己去写的话会需要前后台合作,会大大加大开发的周期,所以考虑使用第三方的即时通...
    ProgrammerChan阅读 8,407评论 16 38
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,498评论 25 707
  • 娜娜啊娜娜 你像天上的流星 心急火燎的飞向我 却又不肯降临 最终选择了无垠夜空 娜娜啊娜娜 你突兀的闯进了我的世界...
    宣丽德阅读 800评论 3 3
  • 我也想开间解忧杂货店,可惜我没有书中那位爷爷厉害。 今年自己的书单上第一本就是解忧杂货店,读完这本书已有好长时间了...
    向上向下阅读 551评论 1 9