455 lines
20 KiB
Markdown
455 lines
20 KiB
Markdown
|
||
以下为您介绍,如何为腾讯云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` | - |
|
||
|
||

|
||
|
||
现在,我们就来动手接入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)。
|
||
|
||

|
||
|
||
### 声明表情文件
|
||
|
||
打开 `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<CustomEmojiFaceData>`,用于将本地图片资源,转换成TUIKit可以接受的格式,后续以 `List` 方式传入。
|
||
|
||
此 `List` 中,每个item都是 `CustomEmojiFaceData`,每个 `CustomEmojiFaceData` 构成一个表情面板中的Tab。具体参数说明如下:
|
||
|
||
```dart
|
||
CustomEmojiFaceData(
|
||
{
|
||
String name, // 文件夹目录名称
|
||
String icon, // Tab中的icon资源文件名
|
||
List<String> list, // 每个图片的文件名,以List
|
||
bool isEmoji // 是否为图片小表情,默认为false,即图片大表情
|
||
}
|
||
);
|
||
```
|
||
|
||
示例代码如下:
|
||
|
||
```dart
|
||
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](https://unicode.org/emoji/charts/full-emoji-list.html) Emoji表情,才需完成本步骤。
|
||
|
||
在您代码定义静态参数或配置的地方,定义一个 `List<Map<String, Object>>` 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<CustomSticker> stickerList; // 表情资源列表
|
||
CustomSticker menuItem; // 表情面包Tab按钮icon
|
||
bool isEmoji; // 是否为图片小表情,默认为图片大表情
|
||
}
|
||
```
|
||
|
||
综上所述,需要写的代码,我们给出示例版本。
|
||
|
||
表情项一演示如何使用Emoji Unicode表情包,表情项二演示如何使用图片类型(包含大或小)表情包。您可以根据需要,使用全部或部分代码。
|
||
|
||
```dart
|
||
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 组件添加表情解析能力
|
||
|
||
>?
|
||
> 本步骤代码示例请[参考此处](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<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` 变量,用于存放图片小表情列表。
|
||
|
||
```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,
|
||
// ......
|
||
),
|
||
// ......
|
||
);
|
||
```
|
||
|
||

|
||
|
||
### STEP4.2: 将表情包能力,注入 TIMUIKitChat
|
||
|
||
将本步骤最开始让您复制的代码方法,传入 `TIMUIKitChat` 组件的 `customStickerPanel` 参数内。
|
||
|
||
```dart
|
||
return TIMUIKitChat(
|
||
customStickerPanel: renderCustomStickerPanel,
|
||
// ......
|
||
);
|
||
```
|
||
|
||
此时,TUIKit表情能力接入完成。您可正常收发测试。如在接入过程中,有任何问题,欢迎随时[联系我们](#contact)。
|
||
|
||
[](id:unicode)
|
||
|
||
## 附录: Emoji Unicode 列表示例
|
||
|
||
本列表仅用于示例演示,您可根据需要,增加或修改。
|
||
|
||
```dart
|
||
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},
|
||
];
|
||
```
|
||
|
||
[](id:contact)
|
||
|
||
## 联系我们
|
||
|
||
If there's anything unclear or you have more ideas, feel free to contact us!
|
||
|
||
- Telegram Group: https://t.me/+1doS9AUBmndhNGNl
|
||
- WhatsApp Group: https://chat.whatsapp.com/Gfbxk7rQBqc8Rz4pzzP27A
|
||
|