以下为您介绍,如何为腾讯云IM Flutter TUIKit引入表情能力。 我们的 `TIMUIKitChat` 组件中,支持发送及接收三种类型的表情: | 表情类型 | 发送形式 | 是否文字混排 | 发送内容 | 解析方式 | 引入方式 | TUIKit默认自带 | |---------|---------|---------|---------|---------|---------|---------| | [Unicode](https://unicode.org/emoji/charts/full-emoji-list.html) Emoji表情 | 文本消息 | 是 | [Unicode](https://unicode.org/emoji/charts/full-emoji-list.html)编码 | 设备自动将[Unicode](https://unicode.org/emoji/charts/full-emoji-list.html)编码解析成小表情。不同的设备,对[Unicode](https://unicode.org/emoji/charts/full-emoji-list.html)解析后的图形,略有不同 | [Unicode](https://unicode.org/emoji/charts/full-emoji-list.html) List | 文档中提供一套[默认Unicode列表示例](#unicode) | | 小图片表情 | 文本消息 | 是 | 表情图片名称 | 根据名称,自动匹配本地Asset图片资源 | 图片资源预存于Asset,并定义 `List` | 一套 QQ 同款小表情图库,可直接使用 | | 大图片表情 | 表情消息 | 否 | `baseURL` 拼接图片文件名,表情图片Asset路径 | 通过路径,解析Asset资源 | 图片资源预存于Asset,并定义 `List` | - | ![](https://qcloudimg.tencent-cloud.cn/raw/bf06763d76d0c6e0c1871a1da401f6ab.png) 现在,我们就来动手接入TUIKit的表情能力。 >? [TUIKit](https://pub.dev/packages/tencent_cloud_chat_uikit)在升级至1.1.0版本后,对表情能力用法有较大改动。请您在升级最新版后,根据本文档指引,重新适配接入表情能力。谢谢~ ## STEP1: 自定义表情图片资源 >? **本步骤选做:** > 如果您需要用到非默认提供的QQ小表情外的其他图片表情,如自定义图片小表情及图片大表情,才需完成本步骤。 > QQ小表情包,TUIKit已自带提供,无需在本步骤引入,请关注后续步骤。 ### 将文件导入项目 请将您的表情资源文件,导入项目的 `assets/custom_face_resource/` 目录内。无论是图片大表情,亦或是图片小表情,都需按此步骤引入。 该目录内,请使用不同的文件夹,区分表情面板中的不同Tab。每个Tab内表情,仅支持一种类型,图片大表情或图片小表情。 文件夹的名称,请使用该Tab的 `name` 命名。该命名不会对客户展现,请根据开发需要,自定义即可。 请保证,所有表情资源文件,不要重名。 此路径的表情图片放置引入,可参考我们的[Demo](https://github.com/TencentCloud/chat-demo-flutter/tree/main/assets/custom_face_resource)。 ![](https://qcloudimg.tencent-cloud.cn/raw/9cf910304e3161bd17336054de3ba7d9.png) ### 声明表情文件 打开 `pubspec.yaml` 文件,在 `flutter` => `assets` 中,声明刚刚引入的表情资源文件。 ```yaml flutter: assets: - assets/custom_face_resource/ ``` ### 在代码中配置图片资源List >? 本步骤代码示例请[参考此处](https://github.com/TencentCloud/chat-demo-flutter/blob/main/lib/utils/constant.dart),直接看 `emojiList` 即可。 在您代码定义静态参数或配置的地方,定义一个 `static List`,用于将本地图片资源,转换成TUIKit可以接受的格式,后续以 `List` 方式传入。 此 `List` 中,每个item都是 `CustomEmojiFaceData`,每个 `CustomEmojiFaceData` 构成一个表情面板中的Tab。具体参数说明如下: ```dart CustomEmojiFaceData( { String name, // 文件夹目录名称 String icon, // Tab中的icon资源文件名 List list, // 每个图片的文件名,以List bool isEmoji // 是否为图片小表情,默认为false,即图片大表情 } ); ``` 示例代码如下: ```dart static final List emojiList = [ // 使用图片小表情,支持图文混排,以文本消息形式发送 CustomEmojiFaceData( name: '4349', icon: "aircraft.png", isEmoji: true, list: [ "aircraft.png", "alarmClock.png", "anger.png", // ... ]), // 使用图片大表情,不支持图文混排,以表情消息形式发送 CustomEmojiFaceData( name: '4350', icon: "menu@2x.png", list: [ "yz00@2x.png", // ... ]), ] ``` ## STEP2: 自定义Emoji Unicode 字符串List >? **本步骤选做:** > 如果您需要用到[Unicode](https://unicode.org/emoji/charts/full-emoji-list.html) Emoji表情,才需完成本步骤。 在您代码定义静态参数或配置的地方,定义一个 `List>` Unicode 列表,供传入。 该列表,我们提供一套示例,在[附录](#unicode)中。 您看直接复制引入这套示例列表,或基于此修改。 ## STEP3: 表情资源预读入内存 >? > 本步骤代码示例请[参考此处](https://github.com/TencentCloud/chat-demo-flutter/blob/main/lib/src/pages/app.dart),直接看 `setCustomSticker` 方法即可。 > QQ小表情包,TUIKit已自带提供,无需在本步骤引入,请关注后续步骤。 在您的项目启动后,首个 `TIMUIKitChat` 组件渲染前,将上一步定义的图片表情资源List,转换成TUIKit表情的实例,放入全局Provider中,存储于内存里。 **本步骤方法仅需执行一次,一次性全部读入内存中。** 因展示渲染表情资源为高频操作,如每次展示前才动态读入内存,对资源与性能占用比较大。 单个表情内存实例,使用 `CustomSticker` 类生成。如果传入了 `unicode` 则为 Unicode Emoji表情,否则为图片类型表情。 ```dart class CustomSticker { int? unicode; // Unicode int值。如果传入了 `unicode` 则为 Unicode Emoji表情,否则为图片类型表情 String name; // 表情名称 int index; // 表情序号 bool isEmoji; // 是否为图片小表情,默认为图片大表情 } ``` 每个Tab的内存实例,使用 `CustomStickerPackage` 类生成。 ```dart class CustomStickerPackage { // 一个系列的表情包定义为一个package,占据一个表情面板Tab String name; // 表情包package name,该Tab文件夹名称。 String? baseUrl; // 表情包package baseUrl,建议配置成:"assets/custom_face_resource/${表情包文件夹名称 即 表情包package name}" List stickerList; // 表情资源列表 CustomSticker menuItem; // 表情面包Tab按钮icon bool isEmoji; // 是否为图片小表情,默认为图片大表情 } ``` 综上所述,需要写的代码,我们给出示例版本。 表情项一演示如何使用Emoji Unicode表情包,表情项二演示如何使用图片类型(包含大或小)表情包。您可以根据需要,使用全部或部分代码。 ```dart setCustomSticker() async { // 定义一个大List来承载各个表情包 package Tab List customStickerPackageList = []; // 表情项一:使用Emoji Unicode表情列表。可以嵌入文字内容中。 // `emojiData` 来自于STEP2。 final defEmojiList = emojiData.asMap().keys.map((emojiIndex) { final emoji = Emoji.fromJson(emojiData[emojiIndex]); return CustomSticker( index: emojiIndex, name: emoji.name, unicode: emoji.unicode); }).toList(); customStickerPackageList.add(CustomStickerPackage( name: "defaultEmoji", stickerList: defEmojiList, menuItem: defEmojiList[0])); // 表情项二:使用您提供的图片表情包。 // 务必保证 `customEmojiPackage.name` 为该Tab文件夹名称。 // `Const.emojiList` 来自于STEP1。 customStickerPackageList.addAll(Const.emojiList.map((customEmojiPackage) { return CustomStickerPackage( name: customEmojiPackage.name, baseUrl: "assets/custom_face_resource/${customEmojiPackage.name}", stickerList: customEmojiPackage.list .asMap() .keys .map((idx) => CustomSticker(index: idx, name: customEmojiPackage.list[idx])) .toList(), menuItem: CustomSticker( index: 0, name: customEmojiPackage.icon, )); }).toList()); Provider.of(context, listen: false) .customStickerPackageList = customStickerPackageList; } ``` ## STEP4: 为 TIMUIKitChat 组件添加表情解析能力 >? > 本步骤代码示例请[参考此处](https://github.com/TencentCloud/chat-demo-flutter/blob/main/lib/src/chat.dart),重点浏览 `renderCustomStickerPanel`, `customStickerPanel` 及 `customEmojiList` 即可。 将以下代码,直接拷贝进入您用于承载 `TIMUIKitChat` 组件的类中。 ```dart Widget renderCustomStickerPanel({ sendTextMessage, sendFaceMessage, deleteText, addCustomEmojiText, addText, List defaultCustomEmojiStickerList = const [], }) { final theme = Provider.of(context).theme; final customStickerPackageList = Provider.of(context).customStickerPackageList; final defaultEmojiList = defaultCustomEmojiStickerList.map((customEmojiPackage) { return CustomStickerPackage( name: customEmojiPackage.name, baseUrl: "assets/custom_face_resource/${customEmojiPackage.name}", isEmoji: customEmojiPackage.isEmoji, isDefaultEmoji: true, stickerList: customEmojiPackage.list .asMap() .keys .map((idx) => CustomSticker(index: idx, name: customEmojiPackage.list[idx])) .toList(), menuItem: CustomSticker( index: 0, name: customEmojiPackage.icon, )); }).toList(); return StickerPanel( sendTextMsg: sendTextMessage, sendFaceMsg: (index, data) => sendFaceMessage(index + 1, (data.split("/")[3]).split("@")[0]), deleteText: deleteText, addText: addText, addCustomEmojiText: addCustomEmojiText, customStickerPackageList: [ ...defaultEmojiList, ...customStickerPackageList ], backgroundColor: theme.weakBackgroundColor, lightPrimaryColor: theme.lightPrimaryColor); } ``` ### STEP4.1: 渲染图片小表情 >? **本步骤选做:** > - 如果您的项目需要用到图片小表情,包括自定义图片小表情,或直接使用默认自带 QQ 同款图片小表情,才需完成本步骤。 > - 图片小表情展现形式和Unicode Emoji类似,建议Unicode Emoji和图片小表情选用一个即可。即,如果您选用了Unicode Emoji,可直接跳过本步骤。 - STEP4.1(a) 为使用自定义图片小表情; - STEP4.1(b) 为使用默认自带 QQ 同款图片小表情。 以上方案,建议直接选用一个方案即可。 如果需要同时使用,请保证您的自定义图片小表情名称,不要和我们默认提供的 QQ 同款图片小表情重复。 #### STEP4.1(a): 添加渲染解析自定义图片小表情的支持 在您用于承载 `TIMUIKitChat` 组件的 `build` 方法中,定义一个 `List customEmojiList` 变量,用于存放图片小表情列表。 ```dart List customEmojiList = Const.emojiList.where((element) => element.isEmoji == true).toList(); ``` 并将此列表,传入 `TIMUIKitChat` 组件的 `customEmojiStickerList` 参数内。 ```dart return TIMUIKitChat( customEmojiStickerList: customEmojiList, // ...... ); ``` >? 如果您用于承载 `TIMUIKitChat` 组件的类为 `StatefulWidget`,您可将 `customEmojiList` 变量,放如State中,仅在首次build时,才去执行 `where` 命令,优化性能。 #### STEP4.1(b): 启用 QQ 小表情包 将 `TIMUIKitChat` 的 `TIMUIKitChatConfig` 的 `isUseDefaultEmoji` 参数,设置为 `true` 即可。此时,会向表情包面板最左侧,自动生成一个承载 QQ 小表情包的 Tab。 ```dart return TIMUIKitChat( config: TIMUIKitChatConfig( isUseDefaultEmoji: true, // ...... ), // ...... ); ``` ![](https://qcloudimg.tencent-cloud.cn/raw/f096cf79710207a0db6f33936a55bbb0.png) ### STEP4.2: 将表情包能力,注入 TIMUIKitChat 将本步骤最开始让您复制的代码方法,传入 `TIMUIKitChat` 组件的 `customStickerPanel` 参数内。 ```dart return TIMUIKitChat( customStickerPanel: renderCustomStickerPanel, // ...... ); ``` 此时,TUIKit表情能力接入完成。您可正常收发测试。如在接入过程中,有任何问题,欢迎随时[联系我们](#contact)。 [](id:unicode) ## 附录: Emoji Unicode 列表示例 本列表仅用于示例演示,您可根据需要,增加或修改。 ```dart List> emojiData = [ {"name": "GRINNING FACE WITH SMILING EYES", "unicode": 128513}, {"name": "FACE WITH TEARS OF JOY", "unicode": 128514}, {"name": "SMILING FACE WITH OPEN MOUTH", "unicode": 128515}, {"name": "SMILING FACE WITH OPEN MOUTH AND SMILING EYES", "unicode": 128516}, {"name": "SMILING FACE WITH OPEN MOUTH AND COLD SWEAT", "unicode": 128517}, { "name": "SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES", "unicode": 128518 }, {"name": "WINKING FACE", "unicode": 128521}, {"name": "SMILING FACE WITH SMILING EYES", "unicode": 128522}, {"name": "FACE SAVOURING DELICIOUS FOOD", "unicode": 128523}, {"name": "RELIEVED FACE", "unicode": 128524}, {"name": "SMILING FACE WITH HEART-SHAPED EYES", "unicode": 128525}, {"name": "SMIRKING FACE", "unicode": 128527}, {"name": "UNAMUSED FACE", "unicode": 128530}, {"name": "FACE WITH COLD SWEAT", "unicode": 128531}, {"name": "PENSIVE FACE", "unicode": 128532}, {"name": "CONFOUNDED FACE", "unicode": 128534}, {"name": "FACE THROWING A KISS", "unicode": 128536}, {"name": "KISSING FACE WITH CLOSED EYES", "unicode": 128538}, {"name": "FACE WITH STUCK-OUT TONGUE AND WINKING EYE", "unicode": 128540}, { "name": "FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES", "unicode": 128541 }, {"name": "DISAPPOINTED FACE", "unicode": 128542}, {"name": "ANGRY FACE", "unicode": 128544}, {"name": "POUTING FACE", "unicode": 128545}, {"name": "CRYING FACE", "unicode": 128546}, {"name": "PERSEVERING FACE", "unicode": 128547}, {"name": "FACE WITH LOOK OF TRIUMPH", "unicode": 128548}, {"name": "DISAPPOINTED BUT RELIEVED FACE", "unicode": 128549}, {"name": "FEARFUL FACE", "unicode": 128552}, {"name": "WEARY FACE", "unicode": 128553}, {"name": "SLEEPY FACE", "unicode": 128554}, {"name": "TIRED FACE", "unicode": 128555}, {"name": "LOUDLY CRYING FACE", "unicode": 128557}, {"name": "FACE WITH OPEN MOUTH AND COLD SWEAT", "unicode": 128560}, {"name": "FACE SCREAMING IN FEAR", "unicode": 128561}, {"name": "ASTONISHED FACE", "unicode": 128562}, {"name": "FLUSHED FACE", "unicode": 128563}, {"name": "DIZZY FACE", "unicode": 128565}, {"name": "FACE WITH MEDICAL MASK", "unicode": 128567}, {"name": "GRINNING CAT FACE WITH SMILING EYES", "unicode": 128568}, {"name": "CAT FACE WITH TEARS OF JOY", "unicode": 128569}, {"name": "SMILING CAT FACE WITH OPEN MOUTH", "unicode": 128570}, {"name": "SMILING CAT FACE WITH HEART-SHAPED EYES", "unicode": 128571}, {"name": "CAT FACE WITH WRY SMILE", "unicode": 128572}, {"name": "KISSING CAT FACE WITH CLOSED EYES", "unicode": 128573}, {"name": "POUTING CAT FACE", "unicode": 128574}, {"name": "CRYING CAT FACE", "unicode": 128575}, {"name": "WEARY CAT FACE", "unicode": 128576}, {"name": "FACE WITH NO GOOD GESTURE", "unicode": 128581}, {"name": "FACE WITH OK GESTURE", "unicode": 128582}, {"name": "PERSON BOWING DEEPLY", "unicode": 128583}, {"name": "SEE-NO-EVIL MONKEY", "unicode": 128584}, {"name": "HEAR-NO-EVIL MONKEY", "unicode": 128585}, {"name": "SPEAK-NO-EVIL MONKEY", "unicode": 128586}, {"name": "HAPPY PERSON RAISING ONE HAND", "unicode": 128587}, {"name": "PERSON RAISING BOTH HANDS IN CELEBRATION", "unicode": 128588}, {"name": "PERSON FROWNING", "unicode": 128589}, {"name": "PERSON WITH POUTING FACE", "unicode": 128590}, {"name": "PERSON WITH FOLDED HANDS", "unicode": 128591}, {"name": "BLACK SCISSORS", "unicode": 9986}, {"name": "WHITE HEAVY CHECK MARK", "unicode": 9989}, {"name": "AIRPLANE", "unicode": 9992}, {"name": "ENVELOPE", "unicode": 9993}, {"name": "RAISED FIST", "unicode": 9994}, {"name": "RAISED HAND", "unicode": 9995}, {"name": "VICTORY HAND", "unicode": 9996}, {"name": "PENCIL", "unicode": 9999}, {"name": "BLACK NIB", "unicode": 10002}, {"name": "HEAVY CHECK MARK", "unicode": 10004}, {"name": "HEAVY MULTIPLICATION X", "unicode": 10006}, {"name": "SPARKLES", "unicode": 10024}, {"name": "EIGHT SPOKED ASTERISK", "unicode": 10035}, {"name": "EIGHT POINTED BLACK STAR", "unicode": 10036}, {"name": "SNOWFLAKE", "unicode": 10052}, {"name": "SPARKLE", "unicode": 10055}, {"name": "CROSS MARK", "unicode": 10060}, {"name": "NEGATIVE SQUARED CROSS MARK", "unicode": 10062}, {"name": "BLACK QUESTION MARK ORNAMENT", "unicode": 10067}, {"name": "WHITE QUESTION MARK ORNAMENT", "unicode": 10068}, {"name": "WHITE EXCLAMATION MARK ORNAMENT", "unicode": 10069}, {"name": "HEAVY EXCLAMATION MARK SYMBOL", "unicode": 10071}, {"name": "HEAVY BLACK HEART", "unicode": 10084}, {"name": "HEAVY PLUS SIGN", "unicode": 10133}, {"name": "HEAVY MINUS SIGN", "unicode": 10134}, {"name": "HEAVY DIVISION SIGN", "unicode": 10135}, {"name": "BLACK RIGHTWARDS ARROW", "unicode": 10145}, {"name": "CURLY LOOP", "unicode": 10160}, {"name": "ROCKET", "unicode": 128640}, {"name": "RAILWAY CAR", "unicode": 128643}, {"name": "HIGH-SPEED TRAIN", "unicode": 128644}, {"name": "HIGH-SPEED TRAIN WITH BULLET NOSE", "unicode": 128645}, {"name": "METRO", "unicode": 128647}, {"name": "STATION", "unicode": 128649}, {"name": "BUS", "unicode": 128652}, {"name": "BUS STOP", "unicode": 128655}, {"name": "AMBULANCE", "unicode": 128657}, {"name": "FIRE ENGINE", "unicode": 128658}, {"name": "POLICE CAR", "unicode": 128659}, {"name": "TAXI", "unicode": 128661}, {"name": "AUTOMOBILE", "unicode": 128663}, {"name": "RECREATIONAL VEHICLE", "unicode": 128665}, {"name": "DELIVERY TRUCK", "unicode": 128666}, {"name": "SHIP", "unicode": 128674}, {"name": "SPEEDBOAT", "unicode": 128676}, {"name": "HORIZONTAL TRAFFIC LIGHT", "unicode": 128677}, {"name": "CONSTRUCTION SIGN", "unicode": 128679}, {"name": "POLICE CARS REVOLVING LIGHT", "unicode": 128680}, {"name": "TRIANGULAR FLAG ON POST", "unicode": 128681}, {"name": "DOOR", "unicode": 128682}, {"name": "NO ENTRY SIGN", "unicode": 128683}, {"name": "SMOKING SYMBOL", "unicode": 128684}, {"name": "NO SMOKING SYMBOL", "unicode": 128685}, {"name": "BICYCLE", "unicode": 128690}, {"name": "PEDESTRIAN", "unicode": 128694}, {"name": "MENS SYMBOL", "unicode": 128697}, {"name": "WOMENS SYMBOL", "unicode": 128698}, {"name": "RESTROOM", "unicode": 128699}, {"name": "BABY SYMBOL", "unicode": 128700}, {"name": "TOILET", "unicode": 128701}, {"name": "WATER CLOSET", "unicode": 128702}, {"name": "BATH", "unicode": 128704}, {"name": "CIRCLED LATIN CAPITAL LETTER M", "unicode": 9410}, {"name": "NEGATIVE SQUARED LATIN CAPITAL LETTER A", "unicode": 127344}, {"name": "NEGATIVE SQUARED LATIN CAPITAL LETTER B", "unicode": 127345}, {"name": "NEGATIVE SQUARED LATIN CAPITAL LETTER O", "unicode": 127358}, {"name": "NEGATIVE SQUARED LATIN CAPITAL LETTER P", "unicode": 127359}, {"name": "NEGATIVE SQUARED AB", "unicode": 127374}, {"name": "SQUARED CL", "unicode": 127377}, {"name": "SQUARED COOL", "unicode": 127378}, {"name": "SQUARED FREE", "unicode": 127379}, {"name": "SQUARED ID", "unicode": 127380}, {"name": "SQUARED NEW", "unicode": 127381}, ]; ``` [](id:contact) ## 联系我们 如果您在接入使用过程中有任何疑问,请扫码加入微信群,或加入QQ群:788910197 咨询。 ![](https://qcloudimg.tencent-cloud.cn/raw/e830ae8c7b8d9253eb71e7c3d9f7b2be.png)