You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter社交应用自定义表情键盘实现方案问询

自定义表情集合实现思路

一、基础映射配置

先把表情编码和资源路径的Map固定好,这是所有逻辑的核心:

final Map<String, String> customEmojis = {
  "#123": "assets/emojis/cat.png",
  "#777": "assets/emojis/dog.png",
  // 按需添加更多表情编码与路径
};

二、输入框(TextFormField)显示表情方案

TextFormField本身无法直接混排文本和图片,用「隐藏输入框+富文本显示」的组合就能解决:

  1. 准备TextEditingController,负责存储实际输入文本(比如"今天#123好可爱#777",存的是表情编码)。
  2. 用Stack布局,底层放透明的TextFormField(设置style: TextStyle(color: Colors.transparent)),处理输入、光标控制;上层放RichText,把控制器里的文本转换成带图片的富文本。
  3. 编写转换函数,把纯文本转成可渲染的InlineSpan列表:
List<InlineSpan> convertTextToEmojiSpans(String text) {
  final spans = <InlineSpan>[];
  final regex = RegExp(r'#\d+'); // 匹配表情编码格式
  int start = 0;

  regex.allMatches(text).forEach((match) {
    // 添加编码前的普通文本
    if (match.start > start) {
      spans.add(TextSpan(text: text.substring(start, match.start)));
    }
    // 匹配到编码则替换为图片
    final emojiCode = match.group(0)!;
    final emojiPath = customEmojis[emojiCode];
    if (emojiPath != null) {
      spans.add(WidgetSpan(
        child: Image.asset(
          emojiPath,
          width: 20,
          height: 20,
          fit: BoxFit.contain,
        ),
      ));
    } else {
      // 找不到对应表情时显示原编码
      spans.add(TextSpan(text: emojiCode));
    }
    start = match.end;
  });

  // 添加剩余的普通文本
  if (start < text.length) {
    spans.add(TextSpan(text: text.substring(start)));
  }
  return spans;
}
  1. 监听TextEditingController的文本变化,实时更新RichText内容。

三、帖子展示时的表情渲染

直接复用上面的转换函数,用RichText渲染帖子内容:

RichText(
  text: TextSpan(
    style: TextStyle(color: Colors.black, fontSize: 16),
    children: convertTextToEmojiSpans(postContent),
  ),
)

如果表情是网络资源,把Image.asset换成Image.network即可。

四、网格表情选择器实现

用GridView.count做布局,每个表情项绑定点击事件,点击时把编码插入到输入框光标位置:

GridView.count(
  crossAxisCount: 5,
  padding: EdgeInsets.all(8),
  children: customEmojis.entries.map((entry) {
    return GestureDetector(
      onTap: () {
        final controller = _yourTextEditingController;
        final emojiCode = entry.key;
        // 获取光标位置并插入编码
        final selection = controller.selection;
        controller.text = controller.text.replaceRange(
          selection.baseOffset,
          selection.extentOffset,
          emojiCode,
        );
        // 更新光标到插入后的位置
        controller.selection = TextSelection.fromPosition(
          TextPosition(offset: selection.baseOffset + emojiCode.length),
        );
      },
      child: Image.asset(
        entry.value,
        width: 30,
        height: 30,
      ),
    );
  }).toList(),
)

额外建议

  • 可以给表情编码加特殊标识(比如[emoji:123]),避免和普通文本里的#数字混淆,正则匹配也更准确。
  • 统一表情图片尺寸,显示时保持一致大小,避免排版混乱。
  • 表情数量较多时,可添加分页或搜索功能,提升选择效率。

内容的提问来源于stack exchange,提问作者Alana Amged

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:25:37