无 UI 集成方案

服务端 API

诚邀爱技术、爱分享的你,成为文档内容共建者> HOT

以下为您介绍,如何为腾讯云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版本后,对表情能力用法有较大改动。请您在升级最新版后,根据本文档指引,重新适配接入表情能力。谢谢~

STEP1: 自定义表情图片资源

说明:

本步骤选做:
如果您需要用到非默认提供的QQ小表情外的其他图片表情,如自定义图片小表情及图片大表情,才需完成本步骤。
QQ小表情包,TUIKit已自带提供,无需在本步骤引入,请关注后续步骤。

将文件导入项目

请将您的表情资源文件,导入项目的 assets/custom_face_resource/ 目录内。无论是图片大表情,抑或是图片小表情,都需按此步骤引入。

该目录内,请使用不同的文件夹,区分表情面板中的不同Tab。每个Tab内表情,仅支持一种类型,图片大表情或图片小表情。

文件夹的名称,请使用该Tab的 name 命名。该命名不会对客户展现,请根据开发需要,自定义即可。

请保证,所有表情资源文件,不要重名。

此路径的表情图片放置引入,可参考我们的Demo

声明表情文件

打开 pubspec.yaml 文件,在 flutter => assets 中,声明刚刚引入的表情资源文件。

flutter:
  assets:
    - assets/custom_face_resource/

在代码中配置图片资源List

说明:

本步骤代码示例请参考此处,直接看 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",
    // ...
  ]),
]

STEP2: 自定义Emoji Unicode 字符串List

说明:

本步骤选做:
如果您需要用到Unicode Emoji表情,才需完成本步骤。

在您代码定义静态参数或配置的地方,定义一个 List<Map<String, Object>> Unicode 列表,供传入。

该列表,我们提供一套示例,在附录中。

您看直接复制引入这套示例列表,或基于此修改。

STEP3: 表情资源预读入内存

说明:


本步骤代码示例请参考此处,直接看 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;
}

STEP4: 为 TIMUIKitChat 组件添加表情解析能力

说明:


本步骤代码示例请参考此处,重点浏览 renderCustomStickerPanel, customStickerPanelcustomEmojiList 即可。

将以下代码,直接拷贝进入您用于承载 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);
}

STEP4.1: 渲染图片小表情

说明:

本步骤选做:

  • 如果您的项目需要用到图片小表情,包括自定义图片小表情,或直接使用默认自带 QQ 同款图片小表情,才需完成本步骤。
  • 图片小表情展现形式和Unicode Emoji类似,建议Unicode Emoji和图片小表情选用一个即可。即,如果您选用了Unicode Emoji,可直接跳过本步骤。
  • STEP4.1(a) 为使用自定义图片小表情;
  • STEP4.1(b) 为使用默认自带 QQ 同款图片小表情。

以上方案,建议直接选用一个方案即可。

如果需要同时使用,请保证您的自定义图片小表情名称,不要和我们默认提供的 QQ 同款图片小表情重复。

STEP4.1(a): 添加渲染解析自定义图片小表情的支持

在您用于承载 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 命令,优化性能。

STEP4.1(b): 启用 QQ 小表情包

TIMUIKitChatTIMUIKitChatConfigisUseDefaultEmoji 参数,设置为 true 即可。此时,会向表情包面板最左侧,自动生成一个承载 QQ 小表情包的 Tab。

return TIMUIKitChat(
    config: TIMUIKitChatConfig(
        isUseDefaultEmoji: true,
        // ......
    ),
    // ......
);

STEP4.2: 将表情包能力,注入 TIMUIKitChat

将本步骤最开始让您复制的代码方法,传入 TIMUIKitChat 组件的 customStickerPanel 参数内。

return TIMUIKitChat(
    customStickerPanel: renderCustomStickerPanel,
    // ......
);

此时,TUIKit表情能力接入完成。您可正常收发测试。如在接入过程中,有任何问题,欢迎随时联系我们

附录: Emoji Unicode 列表示例

本列表仅用于示例演示,您可根据需要,增加或修改。

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},
];

联系我们

如果您在接入使用过程中有任何疑问,请扫码加入微信群,或加入QQ群:788910197 咨询。

目录