首语
最近一直在搞一个 2015 年的项目,需要把对应项目中的环信 2.x 升级到 环信 3.x,而在本项目中使用的环信 SDK 是 3.4.1 版本的。
图片-环信 Hyphenate 3.4.1
而项目中的需求之一就是自定义表情,不使用苹果系统的 Emoji 表情。同时也查了网上的相关资料,发现还是比较少的,所以打算在此记录一下相关笔记。
自定义表情的实质
自定义表情,实际上也是通过发送文本消息一样发送出去,只不过是对文本进行了特殊处理——编码转换。
常见的自定义表情,一般都是提供一组表情素材图片,然后通过编码,将表情素材图片与对应的编码进行一一绑定。无论发送消息还是接收消息时,实际上都是文本消息。通过在本地客户的对消息进行处理,对于发出去的消息,将图片通过一一对应的编码转成文本字符发出去;对于接收的消息,将接收的文本字符转成一一对应的图片进行显示。
自定义表情实现
1、对自定义表情素材图片进行编码转码绑定
① 先导入对应要展示的自定义表情素材图片。
图片 - 自定义表情素材图片导入
② 找到 EaseUI/EMUIKit/Util/
目录下的 EaseConvertToCommonEmoticonsHelper
类,该类主要是处理表情编码的。该类已经默认处理了系统 Emoji 表情的编码转码工作。
③ 对该类进行方法扩展,扩展的方法主要是实现自己自定义表情的编码转码工作。
注意:如果不想侵入 EaseUI 的源码,可以选择通过 Category 扩展的方式进行添加方法。
#pragma mark - EaseConvertToCommonEmoticonsHelper.h
// 自定义表情编码转码
+ (NSDictionary *)emotionsDictionary;
+ (NSArray*)emotionsArray;
#pragma mark - EaseConvertToCommonEmoticonsHelper.m
+ (NSArray*)emotionsArray {
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"[爱你]",@"[奥特曼]",@"[拜拜]",@"[悲伤]",@"[鄙视]",@"[闭嘴]",@"[馋嘴]",@"[吃惊]",@"[打哈欠]",@"[叮]", @"[愤怒]",@"[感冒]",@"[鼓掌]",@"[哈哈]",@"[害羞]",@"[汗]",@"[呵呵]",@"[无语]",@"[哼]",@"[花心]",@"[可爱]",@"[可怜]",@"[酷]",@"[困]",@"[傲慢]", @"[累]",@"[男孩儿]",@"[怒]",@"[怒骂]",@"[女孩儿]",@"[钱]",@"[亲亲]",@"[生病]",@"[失望]",@"[衰]",@"[书呆子]",@"[睡觉]",@"[思考]",@"[太开心]", @"[丢笑]",@"[吐]",@"[兔子]",@"[抠鼻]",@"[委屈]",@"[熊猫]",@"[嘻嘻]",@"[嘘]",@"[阴险]",@"[疑问]",@"[右哼哼]",@"[晕]",@"[抓狂]",@"[猪头]", @"[左怪脸]",@"[左哼哼]",@"[给力]",@"[互粉]",@"[囧]",@"[萌]",@"[神马]",@"[帅]",@"[V5]",@"[囍]",@"[织]",@"[不要]",@"[肥皂]",@"[good]",@"[来]",@"[OK]",@"[拳头]",@"[弱]",@"[握手]",@"[胜利]",@"[赞]",@"[最差]",@"[爱心]",@"[伤心]",@"[冰棍]",@"[蛋糕]",@"[飞机]",@"[风扇]",@"[啤酒]",@"[红领带]",@"[话筒]",@"[咖啡]",@"[蜡烛]",@"[礼物]",@"[绿领带]",@"[汽车]",@"[实习]",@"[手机]",@"[手套]",@"[网球]",@"[围脖]",@"[围观]",@"[帽子]",@"[西瓜]",@"[音乐]",@"[照相]",@"[钟表]",@"[自行车]",@"[足球]",@"[乌云]",@"[落叶]",@"[沙尘暴]",@"[太阳]",@"[微风]",@"[鲜花]", nil];
return array;
}
+ (NSDictionary *)emotionsDictionary {
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"[爱你]",@"[奥特曼]",@"[拜拜]",@"[悲伤]",@"[鄙视]",@"[闭嘴]",@"[馋嘴]",@"[吃惊]",@"[打哈欠]",@"[叮]", @"[愤怒]",@"[感冒]",@"[鼓掌]",@"[哈哈]",@"[害羞]",@"[汗]",@"[呵呵]",@"[无语]",@"[哼]",@"[花心]",@"[可爱]",@"[可怜]",@"[酷]",@"[困]",@"[傲慢]", @"[累]",@"[男孩儿]",@"[怒]",@"[怒骂]",@"[女孩儿]",@"[钱]",@"[亲亲]",@"[生病]",@"[失望]",@"[衰]",@"[书呆子]",@"[睡觉]",@"[思考]",@"[太开心]", @"[丢笑]",@"[吐]",@"[兔子]",@"[抠鼻]",@"[委屈]",@"[熊猫]",@"[嘻嘻]",@"[嘘]",@"[阴险]",@"[疑问]",@"[右哼哼]",@"[晕]",@"[抓狂]",@"[猪头]", @"[左怪脸]",@"[左哼哼]",@"[给力]",@"[互粉]",@"[囧]",@"[萌]",@"[神马]",@"[帅]",@"[V5]",@"[囍]",@"[织]",@"[不要]",@"[肥皂]",@"[good]",@"[来]",@"[OK]",@"[拳头]",@"[弱]",@"[握手]",@"[胜利]",@"[赞]",@"[最差]",@"[爱心]",@"[伤心]",@"[冰棍]",@"[蛋糕]",@"[飞机]",@"[风扇]",@"[啤酒]",@"[红领带]",@"[话筒]",@"[咖啡]",@"[蜡烛]",@"[礼物]",@"[绿领带]",@"[汽车]",@"[实习]",@"[手机]",@"[手套]",@"[网球]",@"[围脖]",@"[围观]",@"[帽子]",@"[西瓜]",@"[音乐]",@"[照相]",@"[钟表]",@"[自行车]",@"[足球]",@"[乌云]",@"[落叶]",@"[沙尘暴]",@"[太阳]",@"[微风]",@"[鲜花]", nil];
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
for (int i=0; i<array.count; i++) {
[dic setObject:[NSString stringWithFormat:@"%03d", i+1] forKey:array[i]];
}
return dic;
}
图片 - EaseConvertToCommonEmoticonsHelper.h 扩展自定义表情编码转码方法
图片 - EaseConvertToCommonEmoticonsHelper.m 扩展自定义表情编码转码方法
2、在 didFinishLaunchingWithOptions 中初始化设置自定义表情相关代码
环信社区中给的参考资料说是尽量放在
HelpDeskUI
中,但是我发现在 环信 3.4.1 中并没有这个类文件,所以就选择了放在didFinishLaunchingWithOptions
中进行初始化设置,从而保证使用。
- 调用了
EaseEmotionEscape
类中的两个方法: - (void) setEaseEmotionEscapePattern:(NSString*)pattern;
- (void) setEaseEmotionEscapeDictionary:(NSDictionary*)dict;
- 这两个方法是保证在聊天发送表情消息时,输入框中显示的是对应的表情,而不是对应的编码字符。必须要设置的。
#pragma mark - AppDelegate.m
[[EaseEmotionEscape sharedInstance] setEaseEmotionEscapePattern:@"\\[[^\\[\\]]{1,3}\\]"];
[[EaseEmotionEscape sharedInstance] setEaseEmotionEscapeDictionary:[EaseConvertToCommonEmoticonsHelper emotionsDictionary]];
图片 - 初始化设置自定义表情相关代码
3、设置聊天界面自定义表情相关代码
在聊天界面,如果需要自定义表情,则需要重写
EaseMessageViewController
类的关于表情的方法:
- (NSArray*)emotionFormessageViewController:(EaseMessageViewController *)viewController;
- 该方法属于
EaseMessageViewControllerDataSource
的代理方法; - @property (weak, nonatomic) id<EaseMessageViewControllerDataSource> dataSource;
- 所以需要记得实现绑定代理协议,否则重写的
emotionFormessageViewController
方法会不执行的: - self.dataSource = self;
/** 替换表情 **/
- (NSArray*)emotionFormessageViewController:(EaseMessageViewController *)viewController {
/** 系统表情(此处本来应该是隐藏的,为了方便看系统表情实现,所以代码暂时未屏蔽,此种情况下显示的,应该是两个表情容器;如果不需要使用系统表情容器,这段代码直接屏蔽即可![](https://diycode.b0.upaiyun.com/photo/2018/08bab5caa05e59f66f3fd5c4e74f969b.png)
[](https://diycode.b0.upaiyun.com/photo/2018/62e3bf4d9164e37f9a20c67532d16534.jpg)
**/
NSMutableArray *emotions = [NSMutableArray array];
for (NSString *name in [EaseEmoji allEmoji]) {
EaseEmotion *emotion = [[EaseEmotion alloc] initWithName:@"" emotionId:name emotionThumbnail:name emotionOriginal:name emotionOriginalURL:@"" emotionType:EMEmotionDefault];
[emotions addObject:emotion];
}
EaseEmotion *temp = [emotions objectAtIndex:0];
EaseEmotionManager *managerDefault = [[EaseEmotionManager alloc] initWithType:EMEmotionDefault emotionRow:3 emotionCol:7 emotions:emotions tagImage:[UIImage imageNamed:temp.emotionId]];
/** 自定义表情 **/
NSMutableArray *emotions2 = [NSMutableArray array];
NSMutableArray *nameArr2 = [NSMutableArray arrayWithCapacity:0];
NSString *name2 = nil;
for (int i=1; i<=[[EaseConvertToCommonEmoticonsHelper emotionsArray] count]; i++) {
name2 = [NSString stringWithFormat:@"%03d",i];
[nameArr2 addObject:name2];
}
int j=0;
for (NSString *name2 in [EaseConvertToCommonEmoticonsHelper emotionsArray]) {
EaseEmotion *emotion = [[EaseEmotion alloc] initWithName:@"" emotionId:name2 emotionThumbnail:nameArr2[j] emotionOriginal:nameArr2[j] emotionOriginalURL:@"" emotionType:EMEmotionPng];
[emotions2 addObject:emotion];
j++;
}
EaseEmotion *temp2 = [emotions2 objectAtIndex:0];
EaseEmotionManager *managerDefault2 = [[EaseEmotionManager alloc] initWithType:EMEmotionPng emotionRow:3 emotionCol:7 emotions:emotions2 tagImage:[UIImage imageNamed:temp2.emotionThumbnail]];
return @[managerDefault, managerDefault2];
}
图片 - 重写 emotionFormessageViewController 方法
4、调整自定义表情容器显示大小
如果需要调整自定义表情容器的显示,则需要找到对应的视图 View。而此处我们则需要找到
EaseUI/EMUIKit/Views/conversation/toolbar/FaceView
目录下的EaseFacialView
类文件,就是在此处进行调整的。
通过此处的代码我们可以了解到,该自定义表情容器 View 是一个
UICollectionView
,且是纵向的,即数据源不是从左向右依次的,而是从上到下,再从左到右依次进行展现的。
此处我们可以对以下涉及位置的
UICollectionView
代理方法进行调整:
- 设置表情尺寸大小:
- (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
- 设置表情容器到边缘距离(会影响到表情间距):
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
- 设置表情行与行之间的间距(注意此时是纵向添加的,所以行与行间距应该是横向的):
- (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
- 设置表情与表情之间的间距(注意此时是纵向添加的,所以表情与表情的间距应该是纵向的):
- (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
此处我这边设置的是表情与表情间间距为 0,行与行之间的间距 15,距离边缘距离顶部、底部各为 5,左侧右侧各为 7.5,而这个左侧右侧的间距 7.5 正好取的是行与行之间间距的一半,防止按页滚动的时候发生偏移。
#pragma mark - EaseFacialView.m
/** 设置表情尺寸大小 **/
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
EaseEmotionManager *emotionManager = [_emotionManagers objectAtIndex:indexPath.section];
NSInteger maxRow = emotionManager.emotionRow;
NSInteger maxCol = emotionManager.emotionCol;
CGFloat itemWidth = self.frame.size.width / maxCol;
CGFloat itemHeight = (self.frame.size.height) / maxRow;
float width = (CGRectGetWidth(self.frame)-7.5*2-(emotionManager.emotionCol-1)*15)/emotionManager.emotionCol;
if (emotionManager.emotionType == EMEmotionPng) {
return CGSizeMake(width,width);
}
return CGSizeMake(itemWidth, itemHeight);
}
/** 设置表情容器到边缘距离(会影响到表情间距) **/
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
EaseEmotionManager *emotionManager = [_emotionManagers objectAtIndex:section];
if (emotionManager.emotionType == EMEmotionPng) {
return UIEdgeInsetsMake(5.f, 7.5f, 5.f, 7.5f);
}
return UIEdgeInsetsMake(0, 0, 0, 0);
}
/** 设置表情行与行之间的间距(注意此时是纵向添加的,所以行与行间距应该是横向的) **/
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
EaseEmotionManager *emotionManager = [_emotionManagers objectAtIndex:section];
if (emotionManager.emotionType == EMEmotionPng) {
return 15.f;
}
return 0.0f;
}
/** 设置表情与表情之间的间距(注意此时是纵向添加的,所以表情与表情的间距应该是纵向的) **/
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
EaseEmotionManager *emotionManager = [_emotionManagers objectAtIndex:section];
if (emotionManager.emotionType == EMEmotionPng) {
return 0.f;
}
return 0.0f;
}
图片 - 调整自定义表情容器显示大小(上)
图片 - 调整自定义表情容器显示大小(下)
网友评论