以下为您介绍,如何为腾讯云IM Flutter TUIKit引入表情能力。
我们的 TIMUIKitChat
组件中,支持发送及接收三种类型的表情:
表情类型 | 发送形式 | 是否文字混排 | 发送内容 | 解析方式 | 引入方式 | TUIKit默认自带 |
---|---|---|---|---|---|---|
Unicode Emoji表情 | 文本消息 | 是 | Unicode编码 | 设备自动将Unicode编码解析成小表情。不同的设备,对Unicode解析后的图形,略有不同 | Unicode List | 文档中提供一套默认Unicode列表示例 |
小图片表情 | 文本消息 | 是 | 表情图片名称 | 根据名称,自动匹配本地Asset图片资源 | 图片资源预存于Asset,并定义 List |
一套 QQ 同款小表情图库,可直接使用 |
大图片表情 | 表情消息 | 否 | baseURL 拼接图片文件名,表情图片Asset路径 |
通过路径,解析Asset资源 | 图片资源预存于Asset,并定义 List |
- |
现在,我们就来动手接入TUIKit的表情能力。
说明:TUIKit在升级至1.1.0版本后,对表情能力用法有较大改动。请您在升级最新版后,根据本文档指引,重新适配接入表情能力。谢谢~
说明:本步骤选做:
如果您需要用到非默认提供的QQ小表情外的其他图片表情,如自定义图片小表情及图片大表情,才需完成本步骤。
QQ小表情包,TUIKit已自带提供,无需在本步骤引入,请关注后续步骤。
请将您的表情资源文件,导入项目的 assets/custom_face_resource/
目录内。无论是图片大表情,抑或是图片小表情,都需按此步骤引入。
该目录内,请使用不同的文件夹,区分表情面板中的不同Tab。每个Tab内表情,仅支持一种类型,图片大表情或图片小表情。
文件夹的名称,请使用该Tab的 name
命名。该命名不会对客户展现,请根据开发需要,自定义即可。
请保证,所有表情资源文件,不要重名。
此路径的表情图片放置引入,可参考我们的Demo。
打开 pubspec.yaml
文件,在 flutter
=> assets
中,声明刚刚引入的表情资源文件。
flutter:
assets:
- assets/custom_face_resource/
说明:本步骤代码示例请参考此处,直接看
emojiList
即可。
在您代码定义静态参数或配置的地方,定义一个 static List<customemojifacedata>
,用于将本地图片资源,转换成TUIKit可以接受的格式,后续以 List
方式传入。
此 List
中,每个item都是 CustomEmojiFaceData
,每个 CustomEmojiFaceData
构成一个表情面板中的Tab。具体参数说明如下:
CustomEmojiFaceData(
{
String name, // 文件夹目录名称
String icon, // Tab中的icon资源文件名
List<String> list, // 每个图片的文件名,以List
bool isEmoji // 是否为图片小表情,默认为false,即图片大表情
}
);
示例代码如下:
static final List<CustomEmojiFaceData> 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",
// ...
]),
]
说明:本步骤选做:
如果您需要用到Unicode Emoji表情,才需完成本步骤。
在您代码定义静态参数或配置的地方,定义一个 List<map<string, object="">>
Unicode 列表,供传入。
该列表,我们提供一套示例,在附录中。
您看直接复制引入这套示例列表,或基于此修改。
说明:
本步骤代码示例请参考此处,直接看setCustomSticker
方法即可。
QQ小表情包,TUIKit已自带提供,无需在本步骤引入,请关注后续步骤。
在您的项目启动后,首个 TIMUIKitChat
组件渲染前,将上一步定义的图片表情资源List,转换成TUIKit表情的实例,放入全局Provider中,存储于内存里。
本步骤方法仅需执行一次,一次性全部读入内存中。 因展示渲染表情资源为高频操作,如每次展示前才动态读入内存,对资源与性能占用比较大。
单个表情内存实例,使用 CustomSticker
类生成。如果传入了 unicode
则为 Unicode Emoji表情,否则为图片类型表情。
class CustomSticker {
int? unicode; // Unicode int值。如果传入了 `unicode` 则为 Unicode Emoji表情,否则为图片类型表情
String name; // 表情名称
int index; // 表情序号
bool isEmoji; // 是否为图片小表情,默认为图片大表情
}
每个Tab的内存实例,使用 CustomStickerPackage
类生成。
class CustomStickerPackage { // 一个系列的表情包定义为一个package,占据一个表情面板Tab
String name; // 表情包package name,该Tab文件夹名称。
String? baseUrl; // 表情包package baseUrl,建议配置成:"assets/custom_face_resource/${表情包文件夹名称 即 表情包package name}"
List<CustomSticker> stickerList; // 表情资源列表
CustomSticker menuItem; // 表情面包Tab按钮icon
bool isEmoji; // 是否为图片小表情,默认为图片大表情
}
综上所述,需要写的代码,我们给出示例版本。
表情项一演示如何使用Emoji Unicode表情包,表情项二演示如何使用图片类型(包含大或小)表情包。您可以根据需要,使用全部或部分代码。
setCustomSticker() async {
// 定义一个大List来承载各个表情包 package Tab
List<CustomStickerPackage> 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<CustomStickerPackageData>(context, listen: false)
.customStickerPackageList = customStickerPackageList;
}
说明:
本步骤代码示例请参考此处,重点浏览renderCustomStickerPanel
,customStickerPanel
及customEmojiList
即可。
将以下代码,直接拷贝进入您用于承载 TIMUIKitChat
组件的类中。
Widget renderCustomStickerPanel({
sendTextMessage,
sendFaceMessage,
deleteText,
addCustomEmojiText,
addText,
List<CustomEmojiFaceData> defaultCustomEmojiStickerList = const [],
}) {
final theme = Provider.of<DefaultThemeData>(context).theme;
final customStickerPackageList =
Provider.of<CustomStickerPackageData>(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);
}
说明:本步骤选做:
- 如果您的项目需要用到图片小表情,包括自定义图片小表情,或直接使用默认自带 QQ 同款图片小表情,才需完成本步骤。
- 图片小表情展现形式和Unicode Emoji类似,建议Unicode Emoji和图片小表情选用一个即可。即,如果您选用了Unicode Emoji,可直接跳过本步骤。
以上方案,建议直接选用一个方案即可。
如果需要同时使用,请保证您的自定义图片小表情名称,不要和我们默认提供的 QQ 同款图片小表情重复。
在您用于承载 TIMUIKitChat
组件的 build
方法中,定义一个 List customEmojiList
变量,用于存放图片小表情列表。
List customEmojiList =
Const.emojiList.where((element) => element.isEmoji == true).toList();
并将此列表,传入 TIMUIKitChat
组件的 customEmojiStickerList
参数内。
return TIMUIKitChat(
customEmojiStickerList: customEmojiList,
// ......
);
说明:如果您用于承载
TIMUIKitChat
组件的类为StatefulWidget
,您可将customEmojiList
变量,放如State中,仅在首次build时,才去执行where
命令,优化性能。
将 TIMUIKitChat
的 TIMUIKitChatConfig
的 isUseDefaultEmoji
参数,设置为 true
即可。此时,会向表情包面板最左侧,自动生成一个承载 QQ 小表情包的 Tab。
return TIMUIKitChat(
config: TIMUIKitChatConfig(
isUseDefaultEmoji: true,
// ......
),
// ......
);
将本步骤最开始让您复制的代码方法,传入 TIMUIKitChat
组件的 customStickerPanel
参数内。
return TIMUIKitChat(
customStickerPanel: renderCustomStickerPanel,
// ......
);
此时,TUIKit表情能力接入完成。您可正常收发测试。如在接入过程中,有任何问题,欢迎随时联系我们。
本列表仅用于示例演示,您可根据需要,增加或修改。
List<Map<String, Object>> 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},
];
</map<string,>
本页内容是否解决了您的问题?